pax_global_header00006660000000000000000000000064123410766630014522gustar00rootroot0000000000000052 comment=75a7b1935ef8bec36752a9c35d6e67d8db2f2653 cadabra-1.39/000077500000000000000000000000001234107666300130335ustar00rootroot00000000000000cadabra-1.39/.ditz-config000066400000000000000000000001611234107666300152470ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/config name: Kasper Peeters email: kasper.peeters@aei.mpg.de issue_dir: bugs cadabra-1.39/.gitignore000066400000000000000000000005031234107666300150210ustar00rootroot00000000000000src/cadabra*.gz doxygen *~ *.o Makefile config.log config.status .depend gui/xcadabra src/cadabra src/test_combinatorics src/test_gmp src/test_lie src/test_preprocessor src/test_tree src/test_xperm src/test_young src/tree_example src/tree_regression_tests tests/*.res tests/*.exp html aclocal.m4 autom4te.cache *.log *.bak cadabra-1.39/AUTHORS000066400000000000000000000002711234107666300141030ustar00rootroot00000000000000Kasper Peeters, with contributions from: José M. Martín-García (the excellent xperm code) James Allen (non-commuting factors patch for @factor_out) cadabra-1.39/COPYING000066400000000000000000000354311234107666300140740ustar00rootroot00000000000000 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 cadabra-1.39/ChangeLog000066400000000000000000001117171234107666300146150ustar00rootroot000000000000002014-05-27 Kasper Peeters * Released 1.39 * Fixed checking for notebook version. 2014-05-26 Kasper Peeters * Released 1.38 * Fixed a sign bug with nested expressions (probably related to the one fixed for 1.36...). 2014-03-25 Kasper Peeters * 1.37 * Fixes for problems flagged by clang. * Released 1.36 * Fixed a bug that made 2*(-A+B) get simplified incorrectly. Thanks to James Mossman for spotting this. 2014-03-15 Kasper Peeters * Released 1.35 * Added 'dvipsnames' to the options for the color package. 2014-03-14 Kasper Peeters * Tagged 1.34 * Modified xperm_new.c -> .cc to not rely on nested functions and variable-sized arrays anymore. This makes it compile with clang. Passes all tests again. 2012-02-18 Kasper Peeters * Released 1.31 * Fixed compilation problems on newer g++ versions having to do with functions hiding virtual base functions. Simplified algorithm base class. 2011-06-27 Kasper Peeters * Released 1.30 2011-06-21 Kasper Peeters * More fixes for @vary. 2011-06-01 Kasper Peeters * Released 1.29 * Fixed compilation problems in tree.hh and youngtab.hh with newer versions of g++. * Fixed bug with @vary acting on derivatives or accented symbols. 2011-04-10 Kasper Peeters * Added 'self' attribute to WeightInherit to allow for dimension counting in which operators have a dimension themselves too. 2011-03-11 Kasper Peeters * Released 1.28 * Fixed printing of "(-1)". 2011-01-16 Kasper Peeters * Released 1.27 * Handle @rewrite_indices on arguments of Derivatives. 2011-01-15 Kasper Peeters * Released 1.26. * Merged in a fix to partially fix @factor_out with tensors (avoids the incorrect mathematical expressions but still requires more work on @rename_dummies to make it generally useful). * Merged in the @factor_out patch by James Allen. This makes it handle non-commuting factors. 2010-12-25 Kasper Peeters * Made @vary work on powers. 2010-12-23 Kasper Peeters * Final fixes for pattern matching with super/sub indices done correctly. This now also fixes replacement rules in which objects with the same name appear both as indices and normal objects on the right-hand side. Documentation on this added. 2010-11-05 Kasper Peeters * Fix of pattern matching of indices of different types, resolving some long-standing problems. * Cleanup of redundant variables and parameters in a number of places. 2010-04-26 Kasper Peeters * Released 1.25 * Disabled messy output of procedure calls in the GUI. * Fixed bug in @eliminate_metric/vielbein which would fail to reset internal variables and thus mess up expressions. 2010-04-25 Kasper Peeters * Released 1.24 * Added handling of dependency information in @eliminate_metric and @eliminate_vielbein. * Fixed parser bug for x**{2} and related expressions, which would introduce spurious brackets. 2010-04-04 Kasper Peeters * Released 1.23 2010-04-01 Kasper Peeters * Fixed bug in @expand_power which would mess up numerical factors. 2010-03-28 Kasper Peeters * Fixed a bug in printing of \pow. * Added setting for brains wired to windows Home/End keys. 2010-03-23 Kasper Peeters * Released 1.22 * Fixed bug in cut-n-paste output of derivatives (which would fail to produce curly brackets and would add a "\," at the end). * Fixed bug that would make canonicalise act on \arrow nodes, with a crash as result. 2010-03-20 Kasper Peeters * Released 1.21 * Fixed canonicalising expressions with anti-commuting indices. * Fixed automatic raising/lowering of indices in canonicalise, and added `position=independent' option for Indices to prevent this from happening when it is not wanted. 2010-03-19 Kasper Peeters * Fixed display of Derivatives and PartialDerivatives (had too many brackets). 2010-03-01 Kasper Peeters * Fixed handling of stuck kernels (both on exit of xcadabra as well as on restart). 2010-02-06 Kasper Peeters * Fixed a substitute bug with a?_{i j} type patterns (would mess up the indices). 2010-02-05 Kasper Peeters * Released 1.19 * Fixed a bunch of undo/redo bugs and associated gtk subtleties which may have been the cause of the OS X segfaults. There are still problems on OS X due to incompatible library versions between Apple and MacPorts/Fink. 2010-02-04 Kasper Peeters * Fixed display of \anticommutator. 2010-02-01 Kasper Peeters * Fixed cadabra-41: @collect_factors does not take commutativity properties into account. 2010-01-28 Kasper Peeters * Fixed cadabra-7. 2009-12-06 Kasper Peeters * Fixed @expand_power action on fractional powers. 2009-12-02 Kasper Peeters * Fixed display of commutators (duplicate second part). 2009-08-26 Kasper Peeters * Fixed compilation problem on OS X. 2009-08-23 Kasper Peeters * Released 1.16 * Fixed a problem with prod-sorting of two neighbouring objects with non-contracted implicit indices. * Fixed split-view operation of the GUI. 2009-08-21 Kasper Peeters * Fixed handling of Accents in the new output routines. 2009-08-18 Kasper Peeters * Released 1.15 2009-07-24 Kasper Peeters * Started refactoring the output in Mathematica and Maple formats. 2009-07-23 Kasper Peeters * Fixed handling of and recovering from LaTeX errors. * Catch more LaTeX errors with user-understandable error dialog (in particular double super/sub script). * Fixed a cell-focus bug. 2009-07-18 Kasper Peeters * Released 1.14 * Fixed buffer underrun problem in the kernel, which would cut input and insert bogus newline characters. 2009-07-17 Kasper Peeters * Released 1.13 * Disabled word-wrapping in input cells to prevent gtk from messing up input at non-symbol boundaries. Added horizontal scroll bar. 2009-06-20 Kasper Peeters * Added safeguard against overwriting existing notebook files. 2009-06-19 Kasper Peeters * Fixed single-factor object pattern replacement bug. 2009-06-15 Kasper Peeters * Faster TeX engine and window reflow on resize added. 2009-06-05 Kasper Peeters * Made @rename_dummies act on single factor terms (traces). 2009-05-31 Kasper Peeters * Released 1.11 2009-05-30 Kasper Peeters * Added experimental drawing of cell boundaries in the GUI. 2009-05-29 Kasper Peeters * Fixed lookup of list properties so that multiple list properties involving the same symbol all get scanned (in progress). * Centralised handling of commutativity properties to make them more robust and uniform. 2009-05-26 Kasper Peeters * Removed auto-deletion of list properties because this messes up constructions of the type {a,b}::AntiCommuting. {a,c}::AntiCommuting. ('a' gets taken out of the first list in that case). 2009-05-25 Kasper Peeters * Made @vary work on isolated non-product terms in a sum too. * Fixed an @unwrap bug which would eliminate accents acting on sums. 2009-05-20 Kasper Peeters * Fixed a problem with derivatives not inheriting CommutingBehaviour correctly. * Removed 'type=grassmann' in Indices, in favour of a more flexible use of AntiCommuting on indices. 2009-04-26 Kasper Peeters * Cleaned up 'can_swap' and fixed handling of ImplicitIndex objects there. 2009-04-14 Kasper Peeters * Added handling of Grassmann derivatives in @prodrule. * Added 'type=grassmann' to the Indices property. * Fixed a bug in the pattern matcher which would match 'a' to 'b^a' under some rare circumstances. 2009-03-28 Kasper Peeters * Made LaTeX errors pop up in a scrollable dialog. * Fixed a display bug leading to superfluous brackets for e.g. "cos(a+b)". 2009-03-22 Kasper Peeters * Fixed handling of brackets in @expand_powers. * Fixed segfault in @expand_powers. 2009-03-18 Kasper Peeters * Fixed a bug which would treat indices with Coordinate property as patterns. 2009-03-17 Kasper Peeters * Added primitive interface to Maxima in the form of the @maxima command. 2009-03-10 Kasper Peeters * Fixed copyright notice. * Released 1.08 2009-02-28 Kasper Peeters * Fixed handling of (a+b)+(c+d) type expressions in @drop/@keep_weight in which c & d have different weight (leading to an undetermined weight for 'c+d'). 2009-02-20 Kasper Peeters * Made @canonicalorder and @acanonicalorder act on single-factor terms as well. * Made '%' to label comments when it occurs at the beginning of a line. 2009-01-28 Kasper Peeters * Fixed another nested partial derivative bug, now in @pintegrate. 2009-01-27 Kasper Peeters * Released 1.07 * Fixed a bug in @unwrap which would make it forget to cleanup nested partial derivatives. 2009-01-23 Kasper Peeters * Released 1.06 * Removed leftover print_recursive_treeform debugging output. 2009-01-22 Kasper Peeters * Released 1.05 * Fixed a bug in @pintegrate. 2009-01-20 Kasper Peeters * Released 1.04. * Fixed a bug in the simplification of fractions, which would make the program crash upon receiving input of the type x_i / (x_k x_k); 2009-01-07 Kasper Peeters * Fixed a bug in the configure script which would make it fail with older versions of glibmm (<2.16). 2008-12-22 Kasper Peeters * Released 1.03 to limited audience. * Weight values can now be arbitrary rational numbers, not just positive integers. * Fixed a bug in @keep_weight and @drop_weight related to negative weights. * Fixed a bug in @keep_weight and @drop_weight which would make the algorithms ignore terms without any weight. 2008-12-14 Kasper Peeters * Fixed a bug in the pattern matcher which would result in incorrect matches when matching indices with tensors of the same name. 2008-11-27 Kasper Peeters * Released 1.0 (time for normal version numbers) * A few small cosmetic changes. 2008-11-26 Kasper Peeters * Released 0.149 * Fixed @distribute to cleanup nests correctly. 2008-11-25 Kasper Peeters * Released 0.148 * Fixed bug related to matching of "A?^{a}" when it would occur as a single item on the lhs of a replacement rule. * Made nested partial derivatives simplify automatically. 2008-10-26 Kasper Peeters * Added window icons. 2008-09-22 Kasper Peeters * Released 0.147 * Fixed a show-stopping brown-paper-bag bug in the GUI. 2008-09-21 Kasper Peeters * Released 0.146 * Various small fixes to prepare for release. 2008-08-29 Kasper Peeters * Released 0.144 * Added undo/redo to the GUI. 2008-08-23 Kasper Peeters * Released 0.142 * Another pattern matching bugfix for cases of the type A^{\mu} B^{\nu}; @substitute!(%)( A?^{\sigma} A?^{\rho} -> Q^{\sigma\rho} ); * Fixed a bug in tree.hh which would sometimes lead to a failure when acting with an algorithm at fixed depth. * Streamlined the pattern matching engine, removing along the way a bug which would misbehave with X Y + Z Z @substitute!(%)( A? A? -> Q ); * Made property initialisation produce proper error messages instead of just textual output. 2008-08-21 Kasper Peeters * Released 0.141 * Fixed a bug in the main loop related to handling of multipliers. * Fixed a bug in @substitute which would touch the tree above the entry point, thereby disabling clean-up routines. 2008-08-07 Kasper Peeters * Fixed a bug in the GUI which would corrupt the notebook upon removing the last cell. 2008-07-20 Kasper Peeters * Started adding @factor_out (not yet completed). 2008-07-19 Kasper Peeters * One last scrolling bug fixed... 2008-07-18 Kasper Peeters * Made some changes to @substitute so that \hasprop can be applied to more general patterns. Added some documentation to the pattern section to explain this. * Changed \div to \frac (though this will eventually go away altogether). 2008-07-16 Kasper Peeters * Fixed scrolling behaviour of the GUI once more... * Fixed a bug in prodcollectnum which would touch the tree above the entry point and thereby broke subtle cases of substitute which relied on the entry point containing a zero multiplier for vanishing terms (see test 6 in defaults.cdb). 2008-07-07 Kasper Peeters * Released 0.139 * Various improvements/fixes to GUI notebook view focus. * Fixed a bug which would leave the tree in inconsistent state after some uses of @unwrap. * Squashed a bug which would apply default rules on the wrong expression. 2008-07-05 Kasper Peeters * Deleting an input cell now correctly re-positions the cursor in the next input cell or open TeX cell. 2008-07-04 Kasper Peeters * Fixed a bug which would make patterns occurring at any level other than the first always be treated as patterns, never as literal. This would mess up @collect_terms on e.g. \commutator{B??}{\commutator{C??}{A??}} + \commutator{C??}{\commutator{B??}{A??}; 2008-07-03 Kasper Peeters * Released 0.138 * Fixed a long-standing bug related to handling of active nodes in default rules. * Fixed display behaviour of \conditional, \unequals and \regex. 2008-07-02 Kasper Peeters * Fixed paste behaviour in the GUI (put cursor after pasted text, disable selection). * Fixed a bug related to canonicalisation of expressions with pattern indices. 2008-06-28 Kasper Peeters * Moved to GIT. 2008-06-27 Kasper Peeters * Separated the source code for the GUI into several files to make it more readable. * Added documentation for reserved node names as well as context-sensitive help for them. 2008-06-26 Kasper Peeters * Added default properties for \commutator to make working with commutators somewhat less non-intuitive. Removed hard-coded \commutator references in the main code. * Fixed a bug with @canonicalise and NonCommuting tensors. 2008-06-24 Kasper Peeters * Made a rare error in dummy index renaming produce a normal error rather than a kernel panic. * Made selections survive pageup/down and home/end. 2008-06-22 Kasper Peeters * Released 0.136. * LaTeX errors now halt a 'run' or 'run from/to cursor'. * Fixed a long-standing bug related to re-declaration of list properties. 2008-06-21 Kasper Peeters * Added autocompletion of greek TeX names as well as some assorted symbols. * Released 0.135 * Added auto-completion of algorithm and property names with TAB in the GUI. 2008-06-20 Kasper Peeters * Released 0.134 as development version. * Fixed a bug in the GUI which made it busy-wait forever when a running mode would be selected in a cell preceding an error cell. 2008-06-18 Kasper Peeters * Made input redirect work in the GUI. * Fixed a bug in the GUI which would lead to a hang after kernel restart. * Fixed a bug with cut-n-paste in the GUI which would always make it insert at the current cursor location, rather than the mouse location. 2008-06-09 Kasper Peeters * Added \dot as a reserved keyword for vector dot products; this prints as \cdot in the GUI and '.' in the text interface. * Added handling of substitution patterns in which patterns have child nodes, as in "A?^{\mu} -> A?". This can be used to remove contracted indices and write them in dot-product like notation. 2008-06-06 Kasper Peeters * Fixed handling of arguments to @factorise. 2008-05-07 Kasper Peeters * Released 0.132. * Fixed various compilation errors when compiling with gcc 4.3.x. 2008-05-06 Kasper Peeters * Added Ctrl-L to vertically center the display in the notebook interface. 2008-05-05 Kasper Peeters * Fixed another bug related to simplification of '1' in products after substitution. 2008-05-02 Kasper Peeters * Fixed a bug in @eliminate_vielbein which would make it fail in certain cases and with InverseVielbein objects. * Fixed handling of f**1 and 1**a. 2008-05-01 Kasper Peeters * Fixed a bug in the GUI which would lead to a mismatch of the internal cell list and the visual representation of it after insertion of a new cell below the current input cell. 2008-04-29 Kasper Peeters * Fixed a bug related to canonicalising of expressions having both Indices and Coordinate or Symbol objects as indices. Fixed a related bug in the index classifier. * Fixed a bug related to handling of pattern matching with indices carrying the Coordinate or Symbol property. 2008-04-05 Kasper Peeters * Fixed compilation problem on Solaris 10. 2008-03-07 Kasper Peeters * Fixed a bug which interpreted numerical indices as dummies (in @eliminate_kr). 2008-02-21 Kasper Peeters * Released 0.130. * Several documentation updates; now more or less complete. * Fixed a long-standing bug which would keep factors of '1' around after substituting symbols with a number. Should also solve some other more obscure bugs related to products with numerical factors. 2008-02-14 Kasper Peeters * Fixed a bug related to dummy relabelling in a substitution rule of which the rhs is a sum with terms containing products with dummies. 2008-02-05 Kasper Peeters * Fixed a bug in replacement of A(2*B) type constructions which would ignore the numerical factor. 2007-12-25 Kasper Peeters * Removed @remove_weyl_traces and @ricci_identity since their functionality has been superseded by @canonicalise and @impose_bianchi respectively, which are more powerful. * Fixed a bug in the preparser which would cut off input lines containing quoted strings with line delimiters. 2007-12-16 Kasper Peeters * Fixed a bug in @dualise_tensor related to dummy index generation, and another one related to the position of the generated indices. 2007-12-10 Kasper Peeters * Fixed two bugs in @einsteinify. 2007-12-02 Kasper Peeters * Added back and forward buttons to the help browser. 2007-11-28 Kasper Peeters * Released 0.128. * Fixed various bugs in the documentation. * Added a NumericalFlat property and a @numerical_flatten algorithm to move numerical factors out of nested operators. * Memory leak/error in xcadabra fixed: - removing cells triggered an invalid read in list::remove; replaced with list::erase now (which is also faster). * Released 0.127 to Fink. 2007-11-27 Kasper Peeters * Added '-S' to the strip command in src/Makefile.in to work around a bug in Leopard's strip. 2007-11-25 Kasper Peeters * Several memory leaks/errors found by valgrind fixed: - property information was not erased at @reset. - xperm.c contained a memcpy for overlapping segments. - xperm.c read usedpoints in schreier_vector without initialising. - index_iterator::operator++ used an end_iterator. - LiE_t read from uninitialised variable in kgetc(). - @breakgendelta modified input pointer but did not pass this back. - @combine used an iterator to an already erased index. - @collect_factors used an iterator after having removed it from fact_hash. * Changed 'echo -n' to 'printf' in configure.in so that it runs on Leopard again. 2007-11-13 Kasper Peeters * Released 0.125 in source form only. * Fixed some more libsigc++ related problems. * Released 0.124 in source form only. * Fixed another small parser bug related to products inside curly brackets. * Fixed a compilation bug with recent versions of libsigc++ (related to SigC::Object now being deprecated). 2007-10-25 Kasper Peeters * Bug in reporting of double & triple indices fixed. 2007-10-16 Kasper Peeters * Fixed a bug related to pattern matching involving coordinate indices in the object and normal indices in the pattern. 2007-10-12 Kasper Peeters * Released 0.123. 2007-10-11 Kasper Peeters * Fixed a bug related to composite indices and @eliminate_kr. This also fixes a bug related to the position of indices after this algorithm has been called. 2007-10-04 Kasper Peeters * Released 0.122 to limited audience. 2007-10-03 Kasper Peeters * Fixed a bug in @prodrule acting on **2. 2007-10-02 Kasper Peeters * Fixed a bug in @young_project_tensor which would make it fail on fully anti-symmetric tensors. 2007-09-27 Kasper Peeters * Released 0.121 to limited audience. * Fixed a stupid bug in @young_project_product which would make it fail on factors which have a projection of only one term. 2007-09-11 Kasper Peeters * Added context-sensitive help (not complete yet). 2007-08-30 Kasper Peeters * Released 0.120 in source form only. * Made wildcard symbols match even when the multiplier does not (in order to match e.g. y**4 with y**n?). 2007-07-25 Kasper Peeters * Fixed textwidth settings resulting in overfull output boxes. * Added more graceful handling of LaTeX errors, and a more user-friendly error dialog for undefined LaTeX expressions. 2007-07-24 Kasper Peeters * Fixed a bug in dependency handling of \pow. 2007-07-22 Kasper Peeters * Updated tutorial 3 in cadabra.tex so that it works in the graphical front-end (using the LaTeXForm property). * Added the LaTeXForm property to enable custom typesetting of objects. * Added saving/loading of settings (font size only for now) in ~/.xcadabra. 2007-07-19 Kasper Peeters * Fixed a fatal cut-n-paste bug when pasting without anything on the clipboard. * Added @tabstandardform. * Made behaviour of "xcadabra filename" more emacs-like when the file does not exist or is not readable. 2007-06-20 Kasper Peeters * Released 0.119. * Fixed a bug in @decompose which would lead to re-computation of an already projected basis. 2007-06-19 Kasper Peeters * Finally fixed the annoying "whitespace inside curly brackets does not turn into a product" bug. * Released 0.119 to limited audience. * Switched @decompose to use @young_project_product. * Temporary files are now created in /tmp and error conditions are caught. 2007-06-18 Kasper Peeters * Fixed a bug in "remove cell" when the last cell of a notebook would be deleted. 2007-06-14 Kasper Peeters * Released 0.117 and 0.118, replaced the hep-th paper. * Fixed a bug in @decompose which would sometimes crash the program (an iterator did not get set correctly at the very end). This fixes the problem with the "make advtest" target. 2007-06-13 Kasper Peeters * Fixed a bug in @decompose which would fail to decompose objects which are identically zero after projection. 2007-06-12 Kasper Peeters * Added handling of Home, End and PageUp/Down keys. * Fixed a bug in collect_factors which would fail to collect objects with non-index sub- or superscripts. * Added !! form of all commands which runs until the expression no longer changes. * Fixed a bug printing derivatives of products when the derivative would not carry a sub- or superscript. 2007-06-11 Kasper Peeters * Fixed a bug handling @expand_power of product expressions. * Fixed a bug in handling of nested partial derivatives without index arguments. * Made the "kernel exited unexpectedly" window give some more information, and restore the cursor shape. * Added brackets around the display of \pow with composite child nodes. 2007-06-07 Kasper Peeters * Released 0.116 to limited audience. * Added a @young_project_product algorithm which projects all tensors in a product in turn, canonicalising at each step, so as to save memory and time. 2007-05-27 Kasper Peeters * Added @tabdimension command. * Fixed several bugs in the Littlewood-Richardson algorithm. * Added the tableaux.sty file and modified the display routines so that Young tableaux can be displayed by the GUI. 2007-05-24 Kasper Peeters * Added FilledTableau property and associated logic in @lr_tensor. * Made @lr_tensor algorithm more flexible. * Released 0.115 2007-05-07 Kasper Peeters * Line spacing in input widgets fixed. * Input cells now always scroll into view when being edited. 2007-05-06 Kasper Peeters * Fixed a bug handling a NonCommuting property when the objects in the list would only differ by the name of an index. This now allows {\psi_{\mu}, \psi_{\nu}}::NonCommuting, even though this is more elegantly written using SelfNonCommuting. 2007-05-04 Kasper Peeters * Released 0.114. * Made cut-n-paste of output cells to input cells work as expected: it pastes the internal cadabra format, not the TeX format as it used to do. Pasting to external applications still pastes the TeX format. 2007-04-30 Kasper Peeters * Released 0.113. * Added @sumsort. 2007-04-27 Kasper Peeters * Released 0.112. * Fixed a bug in @expand_power which gave bogus results for powers <=1. 2007-04-25 Kasper Peeters * Fixed a bug in @join which showed up when using numerical indices or indices which are composite objects. 2007-04-20 Kasper Peeters * Added an option to change the font size in the GUI. * Added more information dialogs (printing, citation info) to the GUI. 2007-04-15 Kasper Peeters * Fixed a bug in @sym/@asym which occurred when the arguments could not be found in the expression. * Fixed stopwatch code and timer updates for the progress bars. 2007-04-13 Kasper Peeters * Fixed a bug in @proplist. 2007-04-11 Kasper Peeters * Released 0.111. * Added some functionality to @join. * Removed spurious debugging output. 2007-04-10 Kasper Peeters * Released 0.110. * Fixed a pattern matching bug with wildcard indices. 2007-04-09 Kasper Peeters * Released 0.109. * Fixed a brown-paper-bag bug in dealing with zero exponents. 2007-04-07 Kasper Peeters * Improved progress indicators. * Rewritten main loop to make it more robust about handling Ctrl-C. Added exception class for Ctrl-C signal handling. 2007-04-06 Kasper Peeters * Better handling of "document modified" flag in the GUI. * Protected the GUI against excessively long output cells which made LaTeX and/or dvipng fail. * Added 'divide cell' option to the GUI. 2007-04-05 Kasper Peeters * Released 0.107. 2007-03-23 Kasper Peeters * Released 0.105. * Fixed a serious bug in @eliminate_metric. 2007-03-22 Kasper Peeters * Released 0.104. 2007-03-20 Kasper Peeters * Canonicalise now generates a strong generating set directly, speeding up the process considerably. 2007-03-19 Kasper Peeters * Fixed a bug in impose_bianchi and updated the routines to use index iterators so they work on proper derivative operators too. 2007-03-16 Kasper Peeters * Added handling of selfdual and anti-selfdual tensors to @all_contractions. * Fixed a bug in searching of properties which would give properties with index wildcard patterns priority over explicit those with explicit patterns. 2007-03-14 Kasper Peeters * Released 0.103. * Added handling of selfdual and anti-selfdual tensors to the Young tableau routines. 2007-03-10 Kasper Peeters * Submitted to Fink. * Released 0.102. * Fixed a bug which made the frontend make a backup of the wrong file upon save or export. 2007-03-09 Kasper Peeters * Fixed a bug in substitute which would leave numerical factors uncollected inside products. * Released 0.101. * Several updates to the reference manual. 2007-03-08 Kasper Peeters * Added logic to deal with arbitrary names for generalised Kronecker delta symbols in handling of EpsilonTensors, as well as the logic to deal with different signatures more consistently (now part of the Metric property). 2007-03-05 Kasper Peeters * Added quit safeguard to the new & open menu items to prevent work from getting lost. 2007-03-03 Kasper Peeters * Added infrastructure for progress bar logic to the gui and kernel (implementation not yet complete). 2007-02-21 Kasper Peeters * Released 0.100. * Fixed a bug which made replacements involving Coordinates do the wrong thing with sub/superscripts and brackets. * Fixed a bug which made \partial_{0}{...} become zero. * Fixed a bug in handling of --input in combination with -F. 2007-02-14 Kasper Peeters * Made parser errors show up correctly in the GUI. 2007-02-07 Kasper Peeters * Released 0.99. 2007-02-06 Kasper Peeters * Removed dependence on the expect library (this was causing too much trouble on many Linux and OS X systems). 2007-02-04 Kasper Peeters * Fixed two errors to make the kernel 64-bit clean. 2007-01-29 Kasper Peeters * Released 0.98. * Added more keyboard shortcuts to the GUI. * Removed the annoying debugging output of the GUI. 2007-01-28 Kasper Peeters * Save/Open dialogs now have default actions. * When starting LaTeX or dvipng inside the GUI, an error could occur which had to do with modglue cleaning up the terminating process (ECHLD returned). Fixed. * Calling @canonicalise on an expression with indices without an index set name would trigger a failed assert. Fixed (thanks to Jeremy Michelson for the bug report). * Fixed various problems in the configure script. 2007-01-25 Kasper Peeters * Released 0.97 and the paper on hep-th 2007-01-25 Kasper Peeters * Fixed a problem in combinatorics.hh related to clear(), which would show up in young_project_tensor. * Fixed bugs in @expand. 2007-01-23 Kasper Peeters * Released 0.96 * Many bug fixes to the kernel and gui, and new examples added. * Debian and RPM packages added. 2007-01-04 Kasper Peeters * Made @young_project use index iterators. 2006-12-12 Kasper Peeters * Released 0.94 to limited audience. * Improvement of the Makefiles and versioning mechanism. * Many improvements to the gui. 2006-12-10 Kasper Peeters * Fixed output of \arrow nodes. * Fixed another missing Inherit in Derivative. 2006-12-07 Kasper Peeters * Changed to the more commonly available Google pcre wrapper for C++ (which is also available as Debian package). 2006-11-30 Kasper Peeters * Released 0.93 * Enabled the graphical frontend (requires the --enable-gui flag to configure). 2006-11-16 Kasper Peeters * Fixed a bug in unwrap which would leave a nested \prod{\prod{}} structure in the tree. 2006-11-16 Kasper Peeters * Released 0.92 * Corrected the documentation and texmacs sample files for the change in the @rename algorithm. * Added the 3rd tutorial as a test case. 2006-11-15 Kasper Peeters * Fixed a bug in @rewrite_diracbar which made the tutorial example 3 fail to run. 2006-11-13 Kasper Peeters * Released 0.91 2006-11-12 Kasper Peeters * Fixed a bug in canonicalise which would not handle equal-length columns of a Young tableau correctly. 2006-11-10 Kasper Peeters * Removed most of PropertyInherit in favour of the new Inherit. 2006-11-09 Kasper Peeters * Finally fixed the bug which made index checking of newly input expressions go wrong. Now always enabled, the CDB_CHECK_INPUT environment variable has gone away. * Fixed a bug which would give wildcard property declarations preference over explicit property declarations, thereby disabling "property specialisation". 2006-11-08 Kasper Peeters * Removed \diff from the defaults. * Fixed several bugs related to the symmetry handling of derivatives and partial derivatives. 2006-10-25 Kasper Peeters * Fixed a bug in handling of bracket types in @distribute. Removed hard-coded node names from @distribute. 2006-10-24 Kasper Peeters * The @prodrule algorithm did not properly un-nest in all cases, now fixed. 2006-10-18 Kasper Peeters * Added a @take_match algorithm to select terms from a sum or list which match a given pattern. 2006-10-15 Kasper Peeters * Added the @take algorithm. * Documented the list algorithms. 2006-10-13 Kasper Peeters * An "infinite recursion" error is now thrown whenever an expression contains a '@' reference to itself. * Rewrote @eliminate_kr to make use of index_iterators, so that it handles indices hidden inside nested operators. 2006-10-11 Kasper Peeters * Made "DiracBar" derive from "Distributable". * Fixed a bug in TeXmacs output for indices. 2006-08-18 Kasper Peeters * Removed dependence on glib. * Various small changes in order to enable compilation on OS X machines. * Version 0.90 released. 2006-08-15 Kasper Peeters * Fixed bug in handling of different index types in canonicalise. * Version 0.88 released. 2006-08-14 Kasper Peeters * Fixed a bug in prodrule with multiple derivatives. * Fixed a bug in handling of nested derivatives. * Version 0.87 released. 2006-08-11 Kasper Peeters * Fixed a bug in substitute which made it forgot to relabel indices already used in subtrees matched by object wildcards. * Version 0.85 released. 2006-08-07 Kasper Peeters * Changed the default logging behaviour to be "off". Setting CDB_LOG now turns on logging. 2006-08-06 Kasper Peeters * Fixed a bug in the property pattern matcher. * Fixed a bug in "unwrap" related to its handling of multiple-argument objects. * Version 0.84 released. 2006-08-03 Kasper Peeters * Some errors in the manual fixed. * Removed all references to the proj++ library. * Now check for gmp in the configure script. * Version 0.83 released. 2006-08-02 Kasper Peeters * Paper submitted to cs.SC. * Version 0.82 released. cadabra-1.39/INSTALL000066400000000000000000000002661234107666300140700ustar00rootroot00000000000000 To install `cadabra', do ./configure make make install as usual. If you want it installed in a different directory than /usr/local, use the --prefix option to configure. cadabra-1.39/Makefile.in000066400000000000000000000077771234107666300151220ustar00rootroot00000000000000 export RELEASE=1.39 export LDFLAGS=@LDFLAGS@ .PHONY: static program_static test fasttest gui gui_static doc ifeq (@enable_gui@,no) all: program install: install_program else all: program gui install: install_program install_gui endif static: program_static program: ( cd src && $(MAKE) ); program_static: ( cd src && $(MAKE) static ); profile: ( export CFLAGS=-pg && export LDFLAGS=-pg && cd src && $(MAKE) ); doc: ( cd doc && $(MAKE) ); gui: ( cd gui && $(MAKE) ); gui_static: ( cd gui && $(MAKE) static ); push_git_public: git push git+ssh://kpeeters@repo.or.cz/srv/git/cadabra.git master push_git_aei: git push kaspercvs:git/cadabra master tarball: git archive --format=tar --prefix=cadabra-${RELEASE}/ HEAD | gzip > ${HOME}/tmp/cadabra-${RELEASE}.tar.gz test: program @echo "==== Running tests ====" ( export CDB_PARANOID=1 && export CDB_ERRORS_ARE_FATAL=1 \ && export CDB_PRINTSTAR=1 && cd tests && $(MAKE) clean && $(MAKE) all); @echo "==== Tests passed =====" @echo "**** Do not forget to run the advanced tests with 'make advtest' ****" fasttest: program @echo "==== Running tests without consistency checks ====" ( export CDB_PRINTSTAR=1 && export CDB_ERRORS_ARE_FATAL=1 && cd tests && $(MAKE) clean && $(MAKE) all); @echo "==== Tests passed =====" @echo "**** Do not forget to run the 'advtest', 'mapletest' and 'maximates' targets ****" advtest: program @echo "==== Running advanced tests (this may take a while) ====" ( export CDB_PARANOID=1 && export CDB_PRINTSTAR=1 && cd tests && $(MAKE) clean && $(MAKE) advanced); @echo "==== Advanced tests passed =====" mapletest: program @echo "==== Running maple dependent tests ====" ( export CDB_PARANOID=1 && export CDB_PRINTSTAR=1 && cd tests && $(MAKE) clean && $(MAKE) maple); @echo "==== Maple tests passed =====" maximatest: program @echo "==== Running maxima dependent tests ====" ( export CDB_PARANOID=1 && export CDB_PRINTSTAR=1 && cd tests && $(MAKE) clean && $(MAKE) maxima); @echo "==== Maxima tests passed =====" install_program: program ( cd src && $(MAKE) install ); @INSTALL@ -d ${DESTDIR}@prefix@/share/man/man1 @INSTALL@ -m 644 man/man1/cadabra.1 ${DESTDIR}@prefix@/share/man/man1 @INSTALL@ -d ${DESTDIR}@prefix@/bin @INSTALL@ -d ${DESTDIR}@prefix@/share/TeXmacs/plugins/cadabra/progs @INSTALL@ -m 644 texmacs/init-cadabra.scm ${DESTDIR}@prefix@/share/TeXmacs/plugins/cadabra/progs @INSTALL@ -d ${DESTDIR}@prefix@/share/texmf/tex/latex/cadabra @INSTALL@ -m 644 doc/cadabra.sty $(DESTDIR)@prefix@/share/texmf/tex/latex/cadabra/cadabra.sty @INSTALL@ -d ${DESTDIR}@prefix@/share/doc/cadabra/properties @INSTALL@ -d ${DESTDIR}@prefix@/share/doc/cadabra/algorithms @INSTALL@ -d ${DESTDIR}@prefix@/share/doc/cadabra/reserved @INSTALL@ -m 644 doc/properties/*.tex ${DESTDIR}@prefix@/share/doc/cadabra/properties @INSTALL@ -m 644 doc/algorithms/*.tex ${DESTDIR}@prefix@/share/doc/cadabra/algorithms @INSTALL@ -m 644 doc/reserved/*.tex ${DESTDIR}@prefix@/share/doc/cadabra/reserved @INSTALL@ -m 644 doc/general.tex ${DESTDIR}@prefix@/share/doc/cadabra/general.tex install_gui: gui ( cd gui && $(MAKE) install ); @INSTALL@ -m 644 man/man1/xcadabra.1 ${DESTDIR}@prefix@/share/man/man1 @INSTALL@ -d ${DESTDIR}@prefix@/share/applications/ @INSTALL@ -d ${DESTDIR}@prefix@/share/pixmaps/ @INSTALL@ -m 644 cadabra.desktop ${DESTDIR}@prefix@/share/applications/cadabra.desktop @INSTALL@ -m 644 cadabra.png ${DESTDIR}@prefix@/share/pixmaps/cadabra.png uninstall: ( cd src && $(MAKE) uninstall ); clean: ( cd src && $(MAKE) clean ); ( cd tests && $(MAKE) clean ); ( cd gui && $(MAKE) clean ); ( cd doc && $(MAKE) clean ); # ( cd deb && rm -Rf usr ); rm -f cadabra*.deb rm -f doc/*~ rm -f *~ rm -f man/man1/*~ distclean: ( cd src && $(MAKE) distclean ); ( cd tests && $(MAKE) distclean ); ( cd gui && $(MAKE) distclean ); ( cd doc && $(MAKE) distclean ); rm -f Makefile config.cache config.log config.status cdb.log aclocal.m4 rm -f cdb*.log tst *~ rm -Rf autom4te.cache depend: ( cd src && $(MAKE) .depend ); ( cd gui && $(MAKE) .depend ); cadabra-1.39/bugs/000077500000000000000000000000001234107666300137735ustar00rootroot00000000000000cadabra-1.39/bugs/issue-0129edd57e7b9ea4932040eeb5d1ba7e83a939db.yaml000066400000000000000000000021301234107666300236040ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Inherit<...> is not flexible enough desc: |- There is an Inherit<...> template which is only useful if an object has a single child, since the other children will simply get ignored. Since a multi-child object will almost always need some computation to be done in order to compute how the multiple properties of the children get converted to a single inherited property, it makes sense to deprecate Inherit<...> altogether, in favour of the [...]Base properties. type: :feature component: cadabra release: reporter: Kasper Peeters status: :in_progress disposition: creation_time: 2009-05-26 17:41:13.764695 Z references: [] id: 0129edd57e7b9ea4932040eeb5d1ba7e83a939db log_events: - - 2009-05-26 17:41:15.118851 Z - Kasper Peeters - created - "" - - 2010-01-15 21:04:09.317656 Z - Kasper Peeters - changed status from unstarted to in_progress - |- Various Inherit properties have been removed, a few still remain in particular on Derivative. cadabra-1.39/bugs/issue-0180195bb345a1d9168742e86b5f9edd57c33937.yaml000066400000000000000000000012501234107666300231630ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Make @canonicalise work on functional arguments desc: |- Right now it is not possible to declare a function f(x,y) symmetric in its two arguments, and then use @canonicalise to simplify it. This should be added, with a suitable notation for Symmetric, AntiSymmetric and friends. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2009-06-29 08:40:38.767074 Z references: [] id: 0180195bb345a1d9168742e86b5f9edd57c33937 log_events: - - 2009-06-29 08:40:39.513109 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-0e5c24e6c9013074288544cc99023cb7674fef2f.yaml000066400000000000000000000012061234107666300232360ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Cleanup output routines desc: |- The output classes are very messy right now, with all sorts of exceptional cases. We should have a separate set of printing classes for each output format, and then also have one set which prints in InputFormat. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2009-06-30 21:45:15.766875 Z references: [] id: 0e5c24e6c9013074288544cc99023cb7674fef2f log_events: - - 2009-06-30 21:45:16.640728 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-1040b3b57b849b9b2cc8fee189ecb0df52544a75.yaml000066400000000000000000000014151234107666300235300ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Varying does not handle single-factor terms. desc: A @vary!(%)( A->a ) on \partial{A} fails. Note that it does work on just 'A'. type: :bugfix component: cadabra release: "1.17" reporter: Kasper Peeters status: :closed disposition: :fixed creation_time: 2009-11-14 14:23:03.351440 Z references: [] id: 1040b3b57b849b9b2cc8fee189ecb0df52544a75 log_events: - - 2009-11-14 14:23:04.225549 Z - Kasper Peeters - created - "" - - 2010-01-23 21:45:03.611977 Z - Kasper Peeters - closed with disposition fixed - |- Should now work for derivatives and accents, as well as nested products. Documentation and test cases updated as well. cadabra-1.39/bugs/issue-15e3e1b9b66a3841c79e43937e91a0f2ada5ae2b.yaml000066400000000000000000000010531234107666300235200ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Cursor position after crash desc: |- After a crash of the kernel in run-all mode of the GUI, the cursor does not end up in the cell which caused the crash. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2008-08-24 11:18:21.421745 Z references: [] id: 15e3e1b9b66a3841c79e43937e91a0f2ada5ae2b log_events: - - 2008-08-24 11:18:23.044185 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-16b3dc7c2f7508a10da63f93e3407730a757908e.yaml000066400000000000000000000012041234107666300232230ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Expanding fractional powers fails. desc: An @expand_power on A**(3/2) produces A*A*A, obviously incorrect. type: :bugfix component: cadabra release: "1.17" reporter: Kasper Peeters status: :closed disposition: :fixed creation_time: 2009-11-14 14:21:52.412089 Z references: [] id: 16b3dc7c2f7508a10da63f93e3407730a757908e log_events: - - 2009-11-14 14:21:53.302036 Z - Kasper Peeters - created - "" - - 2009-12-06 16:10:34.859656 Z - Kasper Peeters - closed with disposition fixed - Fixed in 1.17. cadabra-1.39/bugs/issue-1c7bc5e7512020226c1ca90fb249cab7886b6833.yaml000066400000000000000000000016031234107666300232720ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Implicit indices need to come in normal and conjugate forms. desc: |- Right now, two objects with the same implicit index sitting next to each other are assumed to be connected. However, for e.g. \psi \bar{\chi} with \bar a DiracBar, this is not the case, and the lines go in a different way. In order to determine this, we need to have the concept of indices and conjugate indices. The can_swap routine currently has an exception for DiracBar objects, but this needs to be generalised. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2009-08-23 09:58:30.245616 Z references: [] id: 1c7bc5e7512020226c1ca90fb249cab7886b6833 log_events: - - 2009-08-23 09:58:31.295916 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-1e849154a481bf8a79a06066d104b26efba56381.yaml000066400000000000000000000011561234107666300232260ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Bracket flexibility leads to inconsistencies desc: |- The fact that lists can be written using square and round brackets is a pain for the output routines. Better set on one notation and eliminate a lot of special cases. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2009-06-27 09:57:29.957048 Z references: [] id: 1e849154a481bf8a79a06066d104b26efba56381 log_events: - - 2009-06-27 09:57:30.686868 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-21fdb7347ae291cf9d98ff53c123057a20a0521d.yaml000066400000000000000000000014461234107666300233570ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Ask user before overwriting existing files. desc: |- While the GUI does make backup files before saving, it does not ask the user whether it is ok to overwrite an existing file. That should only be skipped in case of 'Save'; all other write operations should lead to a warning. type: :feature component: cadabra release: reporter: Kasper Peeters status: :closed disposition: :fixed creation_time: 2008-08-25 20:45:28.890368 Z references: [] id: 21fdb7347ae291cf9d98ff53c123057a20a0521d log_events: - - 2008-08-25 20:45:30.226341 Z - Kasper Peeters - created - "" - - 2009-06-20 08:35:16.718008 Z - Kasper Peeters - closed with disposition fixed - "" cadabra-1.39/bugs/issue-2482679b6ec55d83b3f1c431bd7c31047dde8221.yaml000066400000000000000000000013431234107666300233040ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: "@collect_factors does not take commutativity properties into account" desc: |- The following does not do what is expected: {A,B,C,D,E}::NonCommuting. A B D E B A; @prodsort!(%); @collect_factors!(%); type: :bugfix component: cadabra release: "1.18" reporter: Kasper Peeters status: :closed disposition: :fixed creation_time: 2010-01-31 19:29:11.881146 Z references: [] id: 2482679b6ec55d83b3f1c431bd7c31047dde8221 log_events: - - 2010-01-31 19:29:12.696847 Z - Kasper Peeters - created - "" - - 2010-02-05 23:18:30.942177 Z - Kasper Peeters - closed with disposition fixed - "" cadabra-1.39/bugs/issue-248630fcbe40bd59f52429e99de2b43488b5e8b8.yaml000066400000000000000000000013371234107666300234200ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Nested \partial's do not always flatten automatically. desc: |- See test 17 in derivative.cdb. Cleanup_nests is not called at input, which leads to nested partial derivatives which do not automatically simplify. type: :task component: cadabra release: reporter: Kasper Peeters status: :closed disposition: :fixed creation_time: 2008-11-24 22:44:58.390277 Z references: [] id: 248630fcbe40bd59f52429e99de2b43488b5e8b8 log_events: - - 2008-11-24 22:44:59.345048 Z - Kasper Peeters - created - "" - - 2009-01-21 22:39:21.567155 Z - Kasper Peeters - closed with disposition fixed - "" cadabra-1.39/bugs/issue-26a1e390e3639bfcd4eff412054f29beb796a5d3.yaml000066400000000000000000000012771234107666300235410ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: "@sym/@asym duplicate symbols in tree symmetrisation" desc: |- The example A_{a b} B_{c}; @sym!(%){A_{a b}, B_{c}}; leads to a spurious 'B' appearing in the second term. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :closed disposition: :fixed creation_time: 2010-02-27 09:26:56.223896 Z references: [] id: 26a1e390e3639bfcd4eff412054f29beb796a5d3 log_events: - - 2010-02-27 09:26:57.519750 Z - Kasper Peeters - created - "" - - 2010-03-19 18:12:26.308849 Z - Kasper Peeters - closed with disposition fixed - "" cadabra-1.39/bugs/issue-275e6042623fde84879a0c1864f064559562ed3c.yaml000066400000000000000000000013211234107666300231040ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: XCadabra breaks when a .cadabra is present desc: |- When there is .cadabra file present in the user's home directory, xcadabra will fail to start properly. type: :task component: cadabra release: reporter: Kasper Peeters status: :closed disposition: :fixed creation_time: 2008-11-14 10:09:04.301686 Z references: [] id: 275e6042623fde84879a0c1864f064559562ed3c log_events: - - 2008-11-14 10:09:06.640974 Z - Kasper Peeters - created - "" - - 2009-01-21 22:35:58.297210 Z - Kasper Peeters - closed with disposition fixed - Disabled reading of .cadabra when in GUI mode. cadabra-1.39/bugs/issue-2c1e76aeb0f5cf8011ea0bb399c5411e35a1b1e7.yaml000066400000000000000000000015021234107666300235530ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Single-object factors with brackets do not print correctly desc: |- An expression of the type \prod(A){B} does not print correctly (because this is not valid code), yet it gets generated by input of the form (A)*B; Either automatically strip brackets from single factors or do something new with printing; in any case, such expressions will trigger the expression checker and should not be left in the tree. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2009-07-24 13:06:55.101677 Z references: [] id: 2c1e76aeb0f5cf8011ea0bb399c5411e35a1b1e7 log_events: - - 2009-07-24 13:06:56.383716 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-37d2a9206418dbc66533d3b658d17e4ffb5d8ed2.yaml000066400000000000000000000012101234107666300234500ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: TableauSymmetry assigned to a list fails. desc: |- Assigning a TableauSymmetry to a list of items should apply it to each item in turn, but instead it assigns to the list, failing at the parse stage because the \comma node does not have children. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2010-02-08 21:15:49.618081 Z references: [] id: 37d2a9206418dbc66533d3b658d17e4ffb5d8ed2 log_events: - - 2010-02-08 21:15:50.116125 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-38650fc2470a22a6ab2e76ff1b7ebd1f336fa76d.yaml000066400000000000000000000013131234107666300235750ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Re-LaTeX TeX cells on close desc: |- When closing a TeX cell, the content of the output should be updated if the input has changed, and the cell should refuse to close when an error occurs. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :closed disposition: :fixed creation_time: 2009-06-29 08:18:33.674961 Z references: [] id: 38650fc2470a22a6ab2e76ff1b7ebd1f336fa76d log_events: - - 2009-06-29 08:18:34.460887 Z - Kasper Peeters - created - "" - - 2009-06-30 21:43:29.463937 Z - Kasper Peeters - closed with disposition fixed - "" cadabra-1.39/bugs/issue-38a7e972acdc3b14543563da04b16b3968730129.yaml000066400000000000000000000011071234107666300231400ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: "@factor_out does not take into account commutativity properties" desc: |- The @factor_out algorithm moves objects through each other without respecting AntiCommuting or NonCommuting. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2009-08-20 07:57:08.180699 Z references: [] id: 38a7e972acdc3b14543563da04b16b3968730129 log_events: - - 2009-08-20 07:57:09.238755 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-3a0fb777111329baf741dde7dc04fd19ea4885d6.yaml000066400000000000000000000015441234107666300235330ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Multiple-level undo in GUI desc: |- There is at present no undo functionality in the GUI. All actions in the GUI should be undo/redo-able. type: :feature component: cadabra release: reporter: Kasper Peeters status: :closed disposition: :fixed creation_time: 2008-08-24 11:04:49.974071 Z references: [] id: 3a0fb777111329baf741dde7dc04fd19ea4885d6 log_events: - - 2008-08-24 11:04:53.245886 Z - Kasper Peeters - created - "" - - 2008-08-24 11:16:46.047666 Z - Kasper Peeters - changed status from unstarted to in_progress - "" - - 2009-06-03 21:12:16.383914 Z - Kasper Peeters - closed with disposition fixed - Multi-level undo/redo now seems to be working without any major issues. cadabra-1.39/bugs/issue-4db2db8287019b302eafd70dda2d8cdb818f669b.yaml000066400000000000000000000012311234107666300236620ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Eliminating metrics with position-free indices fails. desc: |- This fails: {m, n, p, q, r}::Indices(vector). g_{m n}::Metric. g^{m n}::InverseMetric. obj10:= 3 g_{m p} g^{m p}; @eliminate_metric!(%); but it works with position=fixed for the indices. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2010-02-02 13:13:49.165019 Z references: [] id: 4db2db8287019b302eafd70dda2d8cdb818f669b log_events: - - 2010-02-02 13:13:49.991194 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-4dce789d9676fe7d510b0489a82f68ce21749c73.yaml000066400000000000000000000011401234107666300233460ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Dividing active cell does not work anymore desc: The second half of the cell disappears. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :closed disposition: :fixed creation_time: 2009-06-26 07:47:57.731865 Z references: [] id: 4dce789d9676fe7d510b0489a82f68ce21749c73 log_events: - - 2009-06-26 07:47:58.651440 Z - Kasper Peeters - created - "" - - 2009-08-23 14:11:57.195378 Z - Kasper Peeters - closed with disposition fixed - "" cadabra-1.39/bugs/issue-54b0e71bcc140a8f760bc9835bb6cea84677e76f.yaml000066400000000000000000000010401234107666300235310ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Accents mess up @canonicalise desc: |- \bar{\psi}_g in an expression messes up the canonicaliser, see email on cadabra-discuss d.d. 17-May-2010. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2010-05-18 21:58:20.912820 Z references: [] id: 54b0e71bcc140a8f760bc9835bb6cea84677e76f log_events: - - 2010-05-18 21:58:21.632451 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-583a97dcb71402c9fe6a61f48b4847de22c23900.yaml000066400000000000000000000013561234107666300233170ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Cleanup of numbers in products contains a fatal bug desc: |- The test obj4b:= c - a; @factor_out!(%){a}; leads to a crash similar to the one reported by Molnar. The algorithm creates the tree correctly, but somewhere the cleanup causes problems and makes cadabra crash later down the line when extracting properties in manipulator.cc. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2010-12-27 22:22:02.756136 Z references: [] id: 583a97dcb71402c9fe6a61f48b4847de22c23900 log_events: - - 2010-12-27 22:22:03.748023 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-5c264626947a0e6a9f8b454746ecf7a017f429d0.yaml000066400000000000000000000014321234107666300232450ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Automatic index raising/lowering not handled in @canonicalise desc: |- The @canonicalise algorithm does not yet use the xperm routines which deal with automatic switching of contracted index pairs from upper/lower to lower/upper, e.g. v_a w^a = v^a w_a. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :closed disposition: :fixed creation_time: 2009-06-03 21:14:47.188097 Z references: [] id: 5c264626947a0e6a9f8b454746ecf7a017f429d0 log_events: - - 2009-06-03 21:14:48.182729 Z - Kasper Peeters - created - "" - - 2010-04-04 19:45:37.497846 Z - Kasper Peeters - closed with disposition fixed - Fixed since 1.21. cadabra-1.39/bugs/issue-67f410348cb3e122b6f7541db7fccddb3cc08e9e.yaml000066400000000000000000000013411234107666300236620ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Introduce a notation for 'a range of objects' desc: |- When declaring large sets of indices it would be useful to have a notation which automatically takes care of declaring a range of them, e.g. {a..z}::Indices. or {\alpha..\zeta}::Indices. Since the range operator already exists this should not be too hard. type: :feature component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2008-12-11 16:24:49.469844 Z references: [] id: 67f410348cb3e122b6f7541db7fccddb3cc08e9e log_events: - - 2008-12-11 16:24:50.872368 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-6d586ba4d2e7946ba48f17966355b36375e63b8f.yaml000066400000000000000000000014061234107666300232650ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Accented tensors fail to print desc: |- While \bar{g} is displayed correctly, \bar{g}_{m n} leads to {\bar}{g}\,_{m n} which obviously cannot print. Curly bracket arguments should not lead to separate bracketing of the head node. type: :bugfix component: cadabra release: "1.17" reporter: Kasper Peeters status: :closed disposition: :fixed creation_time: 2009-11-14 14:13:02.897378 Z references: [] id: 6d586ba4d2e7946ba48f17966355b36375e63b8f log_events: - - 2009-11-14 14:13:04.427864 Z - Kasper Peeters - created - "" - - 2009-12-06 11:46:28.187032 Z - Kasper Peeters - closed with disposition fixed - Fixed in 1.17. cadabra-1.39/bugs/issue-871645e20be95eb7b7441170c49d375d770570a0.yaml000066400000000000000000000011211234107666300230640ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Powers do not parse correctly desc: |- The input x**{a} parses as 1: {\pow} 2: {x} 3: {} 4: {a} which is manifestly wrong. Contrast with x**a which works fine. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2010-04-06 18:55:58.464509 Z references: [] id: 871645e20be95eb7b7441170c49d375d770570a0 log_events: - - 2010-04-06 18:55:59.056378 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-88b4ab8f3d8dc4314f47c31b2f9c11a050884367.yaml000066400000000000000000000012141234107666300233050ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Printing problem with \commutator desc: |- \commutator{X}{Y} is stored correctly, but prints [X,YY] instead. type: :bugfix component: cadabra release: "1.17" reporter: Kasper Peeters status: :closed disposition: :fixed creation_time: 2009-11-16 08:16:07.736244 Z references: [] id: 88b4ab8f3d8dc4314f47c31b2f9c11a050884367 log_events: - - 2009-11-16 08:16:08.687917 Z - Kasper Peeters - created - "" - - 2009-12-02 21:23:26.807711 Z - Kasper Peeters - closed with disposition fixed - Fixed in 1.17. cadabra-1.39/bugs/issue-8e86307cac2cf8eb3cf538213e29e428da7cbc1b.yaml000066400000000000000000000012601234107666300236650ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: "@fierz does not work when there are no gamma matrices" desc: |- Fermi-bilinears without gamma matrices do not get handled by @fierz, \bar{\theta} \psi \bar{\epsilon} \chi ; @fierz!(%){ \theta , \chi, \epsilon, \psi}; returns @fierz: not applicable. See email 14-Jun-2010. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2010-06-17 15:05:04.194036 Z references: [] id: 8e86307cac2cf8eb3cf538213e29e428da7cbc1b log_events: - - 2010-06-17 15:05:05.345678 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-9258c825583707f6bf901795c9d4e2a82f13e0d3.yaml000066400000000000000000000016301234107666300231730ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Depends property overwrites earlier ones. desc: |- The following fails: \hat{#}::Accent. \partial{#}::PartialDerivative. A::Depends(\hat). A::Depends(\partial). \hat{A}; @unwrap!(%); Putting all dependencies in one works though. Formalise or fix. type: :bugfix component: cadabra release: "1.17" reporter: Kasper Peeters status: :closed disposition: :wontfix creation_time: 2009-11-14 14:24:01.474019 Z references: [] id: 9258c825583707f6bf901795c9d4e2a82f13e0d3 log_events: - - 2009-11-14 14:24:02.284006 Z - Kasper Peeters - created - "" - - 2010-01-23 21:50:19.691874 Z - Kasper Peeters - closed with disposition wontfix - |- Has been documented now in the Depends documentation. Won't fix for the time being as there is a simple workaround. cadabra-1.39/bugs/issue-96cc2f197c8a31e580777b96155261bdb581005c.yaml000066400000000000000000000015531234107666300231600ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: "'Derivation' property" desc: |- A 'Derivation' should be an object which non-commutes with everything that 'Depends' on it, and for which @prodrule gives D a b c -> (D a) b c + a (D b) c + a b (D c) Moreover, '@prodflatten' should never take the brackets away in these situations. It would be good to have a solution in mind which can easily be extended to work with graded algebras, so that exterior derivatives can be handled with the same logic. type: :feature component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2009-08-18 17:40:13.947979 Z references: [] id: 96cc2f197c8a31e580777b96155261bdb581005c log_events: - - 2009-08-18 17:40:24.472409 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-9bc33d2ce36bc0dd67c03d09cc1c2ab5e9eba099.yaml000066400000000000000000000014771234107666300240210ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Single-factor replacements with dummy names fail. desc: |- The following fails to substitute: {\mu,\nu,\rho,\sigma}::Indices(vector). obj66:= A^{\mu} B^{\nu}; @substitute!!(%)( A?^{\sigma} -> Q^{\sigma} ); Constructions like this do work when the substitution rule contains a product on the lhs. type: :task component: cadabra release: reporter: Kasper Peeters status: :closed disposition: :fixed creation_time: 2008-11-17 12:43:27.027461 Z references: [] id: 9bc33d2ce36bc0dd67c03d09cc1c2ab5e9eba099 log_events: - - 2008-11-17 12:43:40.099941 Z - Kasper Peeters - created - "" - - 2009-06-19 08:42:21.220029 Z - Kasper Peeters - closed with disposition fixed - "" cadabra-1.39/bugs/issue-9c8f132023a13bdea10ef87e26d37d681705a8d1.yaml000066400000000000000000000015001234107666300233510ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Derivatives of sums do not always display correctly in notebook desc: |- While expressions of the type \nabla_{f}{a_{c} d+b_{c}} print correctly, the ones without explicit derivative index, \nabla{a_{c} d+b_{c}}, fail to print brackets. type: :bugfix component: cadabra release: "1.17" reporter: Kasper Peeters status: :closed disposition: :fixed creation_time: 2009-09-02 19:08:55.722106 Z references: [] id: 9c8f132023a13bdea10ef87e26d37d681705a8d1 log_events: - - 2009-09-02 19:09:00.449753 Z - Kasper Peeters - created - "" - - 2010-01-20 21:26:58.387547 Z - Kasper Peeters - closed with disposition fixed - Hopefully finally fixed now, brackets remain somewhat of a hack... cadabra-1.39/bugs/issue-a2bec73e247cc89c7cfca20ee457e5295de9475e.yaml000066400000000000000000000020771234107666300237160ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Deleting last cell of notebook sometimes produces warnings desc: |- Start cadabra, add another cell, then immediately alt-delete it: a gtk warning is produced and the cursor disappears. type: :bugfix component: cadabra release: "1.18" reporter: Kasper Peeters status: :closed disposition: :fixed creation_time: 2009-11-16 08:16:47.368237 Z references: [] id: a2bec73e247cc89c7cfca20ee457e5295de9475e log_events: - - 2009-11-16 08:16:47.975884 Z - Kasper Peeters - created - "" - - 2010-01-28 13:42:29.255930 Z - Kasper Peeters - assigned to release 1.18 from 1.17 - Not quite debugged yet, a few issues remaining. - - 2010-02-05 23:17:55.325477 Z - Kasper Peeters - closed with disposition fixed - |- Also most likely fixes various other redo/undo bugs. Also goes along with removing calls to gtk_update_pending which seems to be problematic in many respects. Might fix the OS X segfaults. cadabra-1.39/bugs/issue-a581c29d3f2a279c34df52be8f4b8761dabc18fa.yaml000066400000000000000000000011531234107666300236710ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Add proper pattern handling to LaTeXForm desc: |- Currently it is not possible to use LaTeXForm for output like M_{a b c} -> {\stackrel{a}{M}}_{b c} because the pattern objects cannot be used in the LaTeXForm string. type: :feature component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2010-05-19 17:03:48.995975 Z references: [] id: a581c29d3f2a279c34df52be8f4b8761dabc18fa log_events: - - 2010-05-19 17:03:49.659672 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-a7f3c6de890010983ccd353a949975bd1b4f66b3.yaml000066400000000000000000000010601234107666300233770ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: "@factor_out does not handle powers" desc: |- A @factor_out on 'q' does not factor out 'q**2'. Workaround: add 'q**2' to the list of symbols to be factored out. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2009-08-20 07:58:05.561128 Z references: [] id: a7f3c6de890010983ccd353a949975bd1b4f66b3 log_events: - - 2009-08-20 07:58:06.547011 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-ada88ddc28be6f0f3567fc2d0f50fb3dc64a37b4.yaml000066400000000000000000000011401234107666300240200ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: "@fierz does not produce useful error messages." desc: |- When calling @fierz on an expression which cannot be Fierz transformed, there are typically no useful error messages about why the algorithm failed. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2009-08-23 09:20:23.538180 Z references: [] id: ada88ddc28be6f0f3567fc2d0f50fb3dc64a37b4 log_events: - - 2009-08-23 09:20:24.547994 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-b5dc914a9876677a3e1059466fd741fb4d2ab336.yaml000066400000000000000000000014541234107666300233260ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Worldsheet susy sample is broken desc: |- LaTeXForm is not handled properly in the worldsheet susy sample notebook. Fixing that messes up the rest of the output... type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :closed disposition: :fixed creation_time: 2010-02-05 21:08:13.684425 Z references: [] id: b5dc914a9876677a3e1059466fd741fb4d2ab336 log_events: - - 2010-02-05 21:08:14.206158 Z - Kasper Peeters - created - "" - - 2010-02-07 21:16:01.735817 Z - Kasper Peeters - closed with disposition fixed - |- Was related to @vary which should now no longer be applied recursively; dropping the exclamation mark did the trick. cadabra-1.39/bugs/issue-b5f5ed9ac93dd64deddecc606872e6a00009d6be.yaml000066400000000000000000000011061234107666300240270ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Kernel hang desc: |- A kernel hang has been reported by Kevin Horton, involving loading a notebook while another one is still in memory. Reproducible on Linux, reported 7-Feb-2010. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2010-02-07 21:49:16.741366 Z references: [] id: b5f5ed9ac93dd64deddecc606872e6a00009d6be log_events: - - 2010-02-07 21:49:17.343213 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-b992ba2a0e28143cf1a66c11a8c4284df71bad33.yaml000066400000000000000000000014361234107666300235040ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Add support for differential 'd' desc: |- While it is possible to use differential 'd' operators by declaring them to be Derivatives, this is far from ideal. We need a special property for this, so that we can write d{#}::DifferentialD. d{s}**2 = -f(r) d{t}**2 + f(r)**(-1) d{r}**2 + r**2 d{\Omega}**2; This will only be really useful once the link to a scalar CAS is added though. type: :feature component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2008-08-29 11:37:06.073877 Z references: [] id: b992ba2a0e28143cf1a66c11a8c4284df71bad33 log_events: - - 2008-08-29 11:37:07.897880 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-becb40c03914860dbc07ef30bb8fb898a9089a73.yaml000066400000000000000000000013131234107666300235250ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: "@eliminate_kr does not work on sums" desc: |- When @eliminate_kr is called on an expression of the form \delta_{a b} * ( more than one term ) the result is inconsistent. type: :task component: cadabra release: reporter: Kasper Peeters status: :closed disposition: :fixed creation_time: 2008-11-14 10:11:36.523033 Z references: [] id: becb40c03914860dbc07ef30bb8fb898a9089a73 log_events: - - 2008-11-14 10:11:37.413111 Z - Kasper Peeters - created - "" - - 2010-01-28 13:40:43.078852 Z - Kasper Peeters - closed with disposition fixed - Fixed in 1.18. cadabra-1.39/bugs/issue-bfc91ba71877919c193cd0b819c17f1d824c29af.yaml000066400000000000000000000010311234107666300234540ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Code redundancy with lhs_contains_dummies desc: |- The lhs_contains_dummies field no longer seems to be used, can it really be discarded? type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2010-11-05 20:41:59.360362 Z references: [] id: bfc91ba71877919c193cd0b819c17f1d824c29af log_events: - - 2010-11-05 20:42:00.224235 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-c4a905e70880ee7899a345ab60a3b86949ff8eae.yaml000066400000000000000000000011051234107666300234750ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Handle PartialDerivatives with no arguments desc: |- When a PartialDerivative is declared and used with only index arguments (no proper object to act on), @canonicalise breaks hard. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2009-06-26 08:04:10.889590 Z references: [] id: c4a905e70880ee7899a345ab60a3b86949ff8eae log_events: - - 2009-06-26 08:04:12.825651 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-c66379cdeaac99c6fb531fb9cb23421ac551c43a.yaml000066400000000000000000000011471234107666300236620ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Unify handling of commutation signs desc: |- There are various pieces of code which deal with commutation signs, mostly in storage.cc and in the @prodrule code. Unify these to handle all cases, and document them. type: :feature component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2009-05-26 18:00:01.714835 Z references: [] id: c66379cdeaac99c6fb531fb9cb23421ac551c43a log_events: - - 2009-05-26 18:00:02.781437 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-c6f19ea6617d8186461181296226988ae7111708.yaml000066400000000000000000000014011234107666300226660ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Numerical indices default to position=free. desc: |- Numerical indices default to position=free and hence n^0 equals n_0. Could probably benefit from a declaration of index properties directly at the level of the tensor, rather than the indices themselves (though this would then require declaration for every tensor, instead of only the index set as currently). type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2009-11-18 00:55:14.615394 Z references: [] id: c6f19ea6617d8186461181296226988ae7111708 log_events: - - 2009-11-18 00:55:16.281256 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-ca0ea385450a3a152cc01829d27cb86d945aca1d.yaml000066400000000000000000000011071234107666300234750ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Pasting from PDF can introduce spurious ctrl-M desc: |- When pasting from PDF on a Mac (and possibly elsewhere), there are spurious ctrl-M characters which mess up the parser. Remove. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2010-05-16 19:31:09.815936 Z references: [] id: ca0ea385450a3a152cc01829d27cb86d945aca1d log_events: - - 2010-05-16 19:31:10.942725 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-d011324da77bbe55d7724d5d0fa87354ee15b87d.yaml000066400000000000000000000007571234107666300234560ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Fix output messages to be TeX desc: "e.g. @collect_terms: not applicable does not print correctly." type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2009-06-27 11:06:33.608356 Z references: [] id: d011324da77bbe55d7724d5d0fa87354ee15b87d log_events: - - 2009-06-27 11:06:34.506656 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-d3968c05090854806ec986d696e99a887d458b18.yaml000066400000000000000000000015531234107666300230750ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Fix dependence on numbers desc: |- A declaration of the type a::Depends(0) will introduce dependence on all rationals (as the overall constant is always ignored). Edit: can be circumvented by using a notation with \partial which mentions the coordinate name, i.e. \partial_{x^{0}}{a} + \partial_{x^{1}}{a}; (see test 37 in tests/fieldtheory.cdb) type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2009-11-18 00:52:35.149705 Z references: [] id: d3968c05090854806ec986d696e99a887d458b18 log_events: - - 2009-11-18 00:52:35.807835 Z - Kasper Peeters - created - "" - - 2010-04-04 19:44:50.433906 Z - Kasper Peeters - edited description - "" cadabra-1.39/bugs/issue-d96ff69906114cf2e375be83d1679277743d6bec.yaml000066400000000000000000000011071234107666300233440ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Repeated divisions are buggy desc: |- Constructions of the type 1/a/b are broken, 1/2/3;1/2/(3+4);1/2/(x+y);1/x/(x+y);1/x/(3+4); will only parse correctly for the first three. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2010-02-08 15:47:47.597689 Z references: [] id: d96ff69906114cf2e375be83d1679277743d6bec log_events: - - 2010-02-08 15:47:48.127740 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-db24f3c504a41ef2463fe34416341f4550b9ed9e.yaml000066400000000000000000000011731234107666300233620ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: PropertyInherit is not universally honoured desc: |- Not all algorithms call head properly when they act on arguments of an object with a given property. PartialDerivative::get_tab is an exception, but many others are not correct. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2010-12-29 17:34:23.746888 Z references: [] id: db24f3c504a41ef2463fe34416341f4550b9ed9e log_events: - - 2010-12-29 17:34:24.506756 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-db53ba8697972d02ee83a31fb26a798f4ef0a7d0.yaml000066400000000000000000000023611234107666300235410ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Eliminate metric acts on non-tensors. desc: |- Calling eliminate_metric on expressions which are not actually tensors still raises/lowers the indices, e.g. {m,n,o}::Indices. \partial{#}::PartialDerivative. g_{m n}::Metric. g^{m n}::InverseMetric. \partial_{i}{g_{m n}} g^{n o}; @eliminate_metric!(%); Fix requires associating a metric wrt. a derivative, e.g. \partial{#}::PartialDerivative(metric=g). \nabla{#}::Derivative(metric=g). etc. Edit: can also fix this by adding a Depends, which looks less clumsy and requires no additional notation: g_{m n}::Depends(\partial). That way we can even handle special cases in which the metric does not depend on coordinates even though in general it would. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2010-02-06 15:33:24.898627 Z references: [] id: db53ba8697972d02ee83a31fb26a798f4ef0a7d0 log_events: - - 2010-02-06 15:33:25.388250 Z - Kasper Peeters - created - "" - - 2010-04-06 14:10:45.734101 Z - Kasper Peeters - edited description - "" cadabra-1.39/bugs/issue-dcc4c5a2bbebd03459ee53b5ebbc6132fe4f560d.yaml000066400000000000000000000012151234107666300240650ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: "@factor_out problems with tensors" desc: |- The @factor_out algorithm does not yet work properly with tensors. This requires on-the-fly index relabelling in the pattern matcher for e.g. A_{m n} D_{m p} Q_{n p} + A_{m n} E_{m p} F_{p q} Q_{n q} type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2008-08-24 11:14:37.655579 Z references: [] id: dcc4c5a2bbebd03459ee53b5ebbc6132fe4f560d log_events: - - 2008-08-24 11:14:39.511710 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-df1fa81e6c1c2d90a3b0ff531a9696ace2a12de3.yaml000066400000000000000000000016051234107666300237270ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Crash with tensors in numerators desc: |- Input of the type x_i / \sqrt{x_k x_k}; leads to an immediate crash in @reduce_div because the tree looks like 1:{\expression} 2: {\prod} 3: {x} 4: _{i} 5: {\frac} 6: {\sqrt} 7: {\prod} 8: {x} 9: _{k} 10: {x} 11: _{k} type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :closed disposition: :fixed creation_time: 2009-01-19 12:06:46.776495 Z references: [] id: df1fa81e6c1c2d90a3b0ff531a9696ace2a12de3 log_events: - - 2009-01-19 12:06:49.273637 Z - Kasper Peeters - created - "" - - 2009-01-21 22:30:48.502918 Z - Kasper Peeters - closed with disposition fixed - "" cadabra-1.39/bugs/issue-e21ce60551528df4aaf0b0226544cd0a2f278e96.yaml000066400000000000000000000010521234107666300233460ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Superfluous square brackets with [..] action desc: |- This produces extra square brackets: @distribute[a*(b+c)]; Wrong flag gets copied somewhere. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2010-02-08 21:17:01.758698 Z references: [] id: e21ce60551528df4aaf0b0226544cd0a2f278e96 log_events: - - 2010-02-08 21:17:02.089206 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-e265d6222f658da087b232a55d9aa05122a523a7.yaml000066400000000000000000000013411234107666300232020ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Redraw segfault on OS X desc: |- When dragging (or resizing?) a window on OS X, the quick successive calls to XCadabra::on_configure_event and the subsequent redraw_cells result in a segfault somewhere inside convert_subset of the TeX engine. Might be because GTK on the mac calls the redraw handler in a different way than on X11. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2009-08-21 09:51:16.723880 Z references: [] id: e265d6222f658da087b232a55d9aa05122a523a7 log_events: - - 2009-08-21 09:51:17.750069 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-f2ada64adc88a3b4014456bc2d50863f242a1f12.yaml000066400000000000000000000030321234107666300234120ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Conversion of / to \frac misplaces bracket types. desc: |- An expression of the form ( 1/\sqrt{2 B b**2} )**2 gets translated to { \frac(1)(\sqrt{2 B b**2}) }**2 whereas it should have been ( \frac{1}{\sqrt{2 B b**2}} )**2 I.e. the brackets around the '/' should sit on the \frac, not on each of the children of \frac. The actual problem sits in preprocessor.cc, which does [a*b] -> \prod[a][b] [a/b] -> \frac[a][b] [a/b]**2 -> \pow{\frac[a][b]}{2} but [\frac{a}{b}] -> \frac{a}{b} [\frac{a}{b}]**2 -> \pow[\frac{a}{b}] So the 'bug' is working the other way around: if you enter things in [\frac{a}{b}] notation, you should expect it to be different from [a/b]. Not sure whether this should be 'fixed'; postponing for the time being. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2010-01-30 20:41:08.452071 Z references: [] id: f2ada64adc88a3b4014456bc2d50863f242a1f12 log_events: - - 2010-01-30 20:41:09.011596 Z - Kasper Peeters - created - "" - - 2010-02-05 00:26:59.500718 Z - Kasper Peeters - edited description - "" - - 2010-02-06 18:10:20.472757 Z - Kasper Peeters - unassigned from release 1.18 - "" - - 2010-02-06 18:12:03.561252 Z - Kasper Peeters - edited description - "" cadabra-1.39/bugs/issue-f51b33b59746c10c94e4beb0dc06977dec195e7c.yaml000066400000000000000000000012231234107666300235330ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: Potential bug with A_{m m} -> replacements desc: |- If the left-hand side of a substitution rule is not a product, some code paths are cut short, potentially messing up dummy replacements in rules which have a dummy pair inside a single tensor on the lhs. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2009-06-19 06:50:38.985389 Z references: [] id: f51b33b59746c10c94e4beb0dc06977dec195e7c log_events: - - 2009-06-19 06:50:40.139415 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/issue-f896ffe43c8b780b98fde4d37b71d683af775a99.yaml000066400000000000000000000014721234107666300236110ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/issue title: "@canonicalise does not honor ImplicitIndex" desc: |- {a,b}::Indices{vector}. {a,b}::Integer(0..3). \Gamma_{a}::ImplicitIndex. \Gamma_{a}\Gamma_{b}-\Gamma_{b}\Gamma_{a}; @prodsort!(%); @canonicalise!(%); @collect_terms!(%); leads to zero. This is because @canonicalise does not honor ImplicitIndex. The logic behind that property is slightly skewed; the TODO file contains ideas on how to fix this properly. type: :bugfix component: cadabra release: reporter: Kasper Peeters status: :unstarted disposition: creation_time: 2009-01-03 00:42:21.402139 Z references: [] id: f896ffe43c8b780b98fde4d37b71d683af775a99 log_events: - - 2009-01-03 00:42:22.802075 Z - Kasper Peeters - created - "" cadabra-1.39/bugs/project.yaml000066400000000000000000000062601234107666300163310ustar00rootroot00000000000000--- !ditz.rubyforge.org,2008-03-06/project name: cadabra version: "0.5" components: - !ditz.rubyforge.org,2008-03-06/component name: cadabra releases: - !ditz.rubyforge.org,2008-03-06/release name: "0.144" status: :released release_time: 2008-08-29 11:39:41.850751 Z log_events: - - 2008-08-29 11:38:36.334943 Z - Kasper Peeters - created - This release has preliminary undo/redo support in the GUI. - - 2008-08-29 11:39:41.850775 Z - Kasper Peeters - released - "" - !ditz.rubyforge.org,2008-03-06/release name: "1.0" status: :released release_time: 2008-12-11 16:25:57.475408 Z log_events: - - 2008-08-29 11:41:30.088931 Z - Kasper Peeters - created - |- The first version with a more or less feature-complete GUI (full documentation and undo/redo). - - 2008-12-11 16:25:57.475432 Z - Kasper Peeters - released - First officially stable release. - !ditz.rubyforge.org,2008-03-06/release name: "1.05" status: :released release_time: 2009-06-03 21:12:40.313354 Z log_events: - - 2009-01-21 22:42:59.204261 Z - Kasper Peeters - created - Fixes bugs related to handling of fractions and partial integration. - - 2009-06-03 21:12:40.313385 Z - Kasper Peeters - released - "" - !ditz.rubyforge.org,2008-03-06/release name: "1.12" status: :released release_time: 2009-08-18 17:37:31.895514 Z log_events: - - 2009-06-03 21:11:35.181237 Z - Kasper Peeters - created - "" - - 2009-08-18 17:37:31.895540 Z - Kasper Peeters - released - Long ago... - !ditz.rubyforge.org,2008-03-06/release name: "1.15" status: :released release_time: 2009-08-18 17:37:56.437346 Z log_events: - - 2009-08-18 17:37:15.979707 Z - Kasper Peeters - created - Stable version release before Ubuntu Karmic 9.10 freeze. - - 2009-08-18 17:37:56.437371 Z - Kasper Peeters - released - "" - !ditz.rubyforge.org,2008-03-06/release name: "1.17" status: :released release_time: 2010-01-28 13:43:06.931548 Z log_events: - - 2009-09-02 19:07:21.289887 Z - Kasper Peeters - created - "" - - 2010-01-28 13:43:06.931573 Z - Kasper Peeters - released - Released on PPA and as source only. - !ditz.rubyforge.org,2008-03-06/release name: "1.18" status: :released release_time: 2010-02-06 18:10:31.298472 Z log_events: - - 2010-01-28 13:41:27.478216 Z - Kasper Peeters - created - to be uploaded to Debian in time for Ubuntu Lucid freeze - - 2010-02-06 18:10:31.298499 Z - Kasper Peeters - released - "" - !ditz.rubyforge.org,2008-03-06/release name: "1.21" status: :unreleased release_time: log_events: - - 2010-02-07 21:17:02.868424 Z - Kasper Peeters - created - "" cadabra-1.39/cadabra.desktop000066400000000000000000000003421234107666300160020ustar00rootroot00000000000000[Desktop Entry] Name=Cadabra GenericName=Cadabra computer algebra system Comment=Computer algebra system for field theory problems Icon=cadabra Type=Application Categories=Math;Science;Education; Exec=xcadabra Terminal=false cadabra-1.39/cadabra.png000066400000000000000000000071411234107666300151210ustar00rootroot00000000000000PNG  IHDR@@iqsBIT|d pHYsM]tEXtSoftwarewww.inkscape.org< IDATx[kuntVoh7ZIB;.*ą1Eq JU슋8EB86c;TT2ˑqQXjc~l}|v0LlRV nWfj:=:w 558%_;s^" dID&2 d`rgs*mn @Š> ĉv6v0bZr( r8\7iC\:V&y}f(1ui~=Oz5o^_6Q@.B".:o(@{15Y鰥t~sB5A,!,p! h_B"H)~NŴ" RXzc'(gG|'rs^C߆W"~~:)~"uNcr+~!ESH4 ,ND*?QC^d/V:-? Dz :1ȴ9;@ ]^BEr:,~^ _BBfa@$r;y@ޕ?Cv?:Qp@ @Ж V֦֩ǻr1J+,n Z9"!^7WWWR%#mLɮPUC۪UrrH;]]|f,3㐟M#ϕZzJO˅_TkbJ³z.]U.W&+O -'?.*ͽ3wn ת SoSs278rsfM6ݛ.O#{n٥,m.,엻䊲UY#RE5ik tL@_ЙSh#0"uZ'SnІK.?@m1hC_^k}AGfgyXṉ@$U7>']?îjyoO8AV=ۍ&G3rEVîE5"݆= @ &ٵ;>?t@TK@-}Uj:$z.,℉M.c=9y0pePYdP`LRs.~w>{OQ$MŽ?Q+MYJ_^O- 3O4{ҭb,uɤZhp!紅4K (O-ZBhw2c' gz1CDK/^nlk{B"\꒬2(UNZAAy~upr-V-bƂh )+z@8{|܊tFi? xOmKQC-8rX +^Ň`)l_20%~08{uF'͝/ϐIH" O=t|ճܒlT\;W'}:sS5"2q}sqk:$eՖ쭑~azo7əJ,}Vz 1W c}Z\2R1sSU\VVU"ǩ 7ʕG+2M'I~TJsvY+ =fll=*dk!d*q]bs물Ơ; ݭ}T|)FXB7ñ@UJ6EWLD?Syh;!ʼn_@6-lgtnH~:pɽɂ?=RXD#dP}]ߑ{rVh@&媿n7ϘPF@R ]næ C ?=9&@8O驩/sgcy}_|;_ޑtژ6 &o5n]˲%NMza)Ps|}F:1(W)Q.QO6nu<ŀб\R%{CrK&U+DYe"2Ah.*W@JKKPaT> E_.Dָr>! 78>w( Ve J021%H u㼱"{9>7CD?pAa)ց(<*Eq3g"ck;È(lerz˜=>e*Mh>c4%b}P>|,~+|gSDd9__퐐":lj=bvH%vonc/9J!<.K]$q){%:*ɿv}1tOFhGJ2`O?{lQ5@Ck' DPa1F]`&˨!w5sDޣ7i}7rSx(e4!Ѿ\IENDB`cadabra-1.39/cadabra.svg000066400000000000000000000174321234107666300151400ustar00rootroot00000000000000 image/svg+xml cadabra-1.39/configure000077500000000000000000006012631234107666300147520ustar00rootroot00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.65. # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error ERROR [LINENO LOG_FD] # --------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with status $?, using 1 if that was 0. as_fn_error () { as_status=$?; test $as_status -eq 0 && as_status=1 if test "$3"; then as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 fi $as_echo "$as_me: error: $1" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= PACKAGE_URL= ac_unique_file="src/storage.cc" ac_default_prefix=/usr/local # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS GLIBMM_VER GTKMM_VER NESTED pcrecpp MAC_OS_X enable_gui LATEX DVIPNG pangomm_LIBS pangomm_CFLAGS GLIBMM_LIBS GLIBMM_CFLAGS GTKMM_LIBS GTKMM_CFLAGS pango_LIBS pango_CFLAGS gtk_LIBS gtk_CFLAGS PTYWRAP modglue_LIBS modglue_CFLAGS sigc_LIBS sigc_CFLAGS PKG_CONFIG EGREP GREP CXXCPP LIE install_flags INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM SET_MAKE LN_S ac_ct_CXX CXXFLAGS CXX OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_runtime_dependency_check enable_gui ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CXX CXXFLAGS CCC CXXCPP PKG_CONFIG sigc_CFLAGS sigc_LIBS modglue_CFLAGS modglue_LIBS gtk_CFLAGS gtk_LIBS pango_CFLAGS pango_LIBS GTKMM_CFLAGS GTKMM_LIBS GLIBMM_CFLAGS GLIBMM_LIBS pangomm_CFLAGS pangomm_LIBS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error "unrecognized option: \`$ac_option' Try \`$0 --help' for more information." ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-runtime-dependency-check Enable check for runtime dependencies (default is yes) --enable-gui Enable building of the graphical front-end (default is yes) Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CXX C++ compiler command CXXFLAGS C++ compiler flags CXXCPP C++ preprocessor PKG_CONFIG path to pkg-config utility sigc_CFLAGS C compiler flags for sigc, overriding pkg-config sigc_LIBS linker flags for sigc, overriding pkg-config modglue_CFLAGS C compiler flags for modglue, overriding pkg-config modglue_LIBS linker flags for modglue, overriding pkg-config gtk_CFLAGS C compiler flags for gtk, overriding pkg-config gtk_LIBS linker flags for gtk, overriding pkg-config pango_CFLAGS C compiler flags for pango, overriding pkg-config pango_LIBS linker flags for pango, overriding pkg-config GTKMM_CFLAGS C compiler flags for GTKMM, overriding pkg-config GTKMM_LIBS linker flags for GTKMM, overriding pkg-config GLIBMM_CFLAGS C compiler flags for GLIBMM, overriding pkg-config GLIBMM_LIBS linker flags for GLIBMM, overriding pkg-config pangomm_CFLAGS C compiler flags for pangomm, overriding pkg-config pangomm_LIBS linker flags for pangomm, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.65 Copyright (C) 2009 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_cxx_try_cpp LINENO # ------------------------ # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } >/dev/null && { test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_cxx_try_cpp # ac_fn_cxx_check_header_mongrel LINENO HEADER VAR INCLUDES # --------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_cxx_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_cxx_check_header_mongrel # ac_fn_cxx_try_run LINENO # ------------------------ # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_cxx_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_cxx_try_run # ac_fn_cxx_check_header_compile LINENO HEADER VAR INCLUDES # --------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_cxx_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_cxx_check_header_compile cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.65. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------------- ## ## File substitutions. ## ## ------------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then ac_site_file1=$CONFIG_SITE elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "no acceptable C compiler found in \$PATH See \`config.log' for more details." "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { as_fn_set_status 77 as_fn_error "C compiler cannot create executables See \`config.log' for more details." "$LINENO" 5; }; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if test "${ac_cv_objext+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "cannot compute suffix of object files: cannot compile See \`config.log' for more details." "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if test "${ac_cv_c_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if test "${ac_cv_prog_cc_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if test "${ac_cv_prog_cc_c89+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if test "${ac_cv_cxx_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if test "${ac_cv_prog_cxx_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do for ac_t in install-sh install.sh shtool; do if test -f "$ac_dir/$ac_t"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/$ac_t -c" break 2 fi done done if test -z "$ac_aux_dir"; then as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' ac_config_headers="$ac_config_headers src/config.h" ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu # Figure out how to turn on compiler warnings. { $as_echo "$as_me:${as_lineno-$LINENO}: checking CFLAGS for maximum warnings" >&5 $as_echo_n "checking CFLAGS for maximum warnings... " >&6; } if test "${ac_cv_cflags_warn_all+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_cflags_warn_all="no, unknown" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_save_CFLAGS="$CFLAGS" for ac_arg in "-pedantic % -Wall" "-xstrconst % -v" "-std1 % -verbose -w0 -warnprotos" "-qlanglvl=ansi % -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" "-ansi -ansiE % -fullwarn" "+ESlit % +w1" "-Xc % -pvctl,fullmsg" "-h conform % -h msglevel 2" # do CFLAGS="$ac_save_CFLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_cflags_warn_all=`echo $ac_arg | sed -e 's,.*% *,,'` ; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext done CFLAGS="$ac_save_CFLAGS" ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cflags_warn_all" >&5 $as_echo "$ac_cv_cflags_warn_all" >&6; } case ".$ac_cv_cflags_warn_all" in .ok|.ok,*) ;; .|.no|.no,*) ;; *) if echo " $CFLAGS " | grep " $ac_cv_cflags_warn_all " 2>&1 >/dev/null then { { $as_echo "$as_me:${as_lineno-$LINENO}: : CFLAGS does contain \$ac_cv_cflags_warn_all"; } >&5 (: CFLAGS does contain $ac_cv_cflags_warn_all) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } else { { $as_echo "$as_me:${as_lineno-$LINENO}: : CFLAGS=\"\$CFLAGS \$ac_cv_cflags_warn_all\""; } >&5 (: CFLAGS="$CFLAGS $ac_cv_cflags_warn_all") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } CFLAGS="$CFLAGS $ac_cv_cflags_warn_all" fi ;; esac # Check whether --enable-runtime-dependency-check was given. if test "${enable_runtime_dependency_check+set}" = set; then : enableval=$enable_runtime_dependency_check; else check_runtime_dependencies=yes fi if test "$check_runtime_dependencies" == "yes" then # Extract the first word of "lie", so it can be a program name with args. set dummy lie; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_LIE+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$LIE"; then ac_cv_prog_LIE="$LIE" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_LIE="yes" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_LIE" && ac_cv_prog_LIE="no" fi fi LIE=$ac_cv_prog_LIE if test -n "$LIE"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIE" >&5 $as_echo "$LIE" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "${LIE}" == "no" then as_fn_error "Need the LiE program; get it from http://young.sp2mi.univ-poitiers.fr/~marc/LiE/ ." "$LINENO" 5 fi fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 $as_echo_n "checking how to run the C++ preprocessor... " >&6; } if test -z "$CXXCPP"; then if test "${ac_cv_prog_CXXCPP+set}" = set; then : $as_echo_n "(cached) " >&6 else # Double quotes because CXXCPP needs to be expanded for CXXCPP in "$CXX -E" "/lib/cpp" do ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CXXCPP=$CXXCPP fi CXXCPP=$ac_cv_prog_CXXCPP else ac_cv_prog_CXXCPP=$CXXCPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 $as_echo "$CXXCPP" >&6; } ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "C++ preprocessor \"$CXXCPP\" fails sanity check See \`config.log' for more details." "$LINENO" 5; } fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if test "${ac_cv_path_GREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if test "${ac_cv_path_EGREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if test "${ac_cv_header_stdc+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_cxx_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_cxx_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " eval as_val=\$$as_ac_Header if test "x$as_val" = x""yes; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in pcre.h do : ac_fn_cxx_check_header_mongrel "$LINENO" "pcre.h" "ac_cv_header_pcre_h" "$ac_includes_default" if test "x$ac_cv_header_pcre_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PCRE_H 1 _ACEOF fi done if test "${ac_cv_header_pcre_h}" == "no" then as_fn_error "Need the pcre library; get it from http://www.pcre.org/ . Make sure to set CPPFLAGS if necessary." "$LINENO" 5 fi for ac_header in gmpxx.h do : ac_fn_cxx_check_header_mongrel "$LINENO" "gmpxx.h" "ac_cv_header_gmpxx_h" "$ac_includes_default" if test "x$ac_cv_header_gmpxx_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GMPXX_H 1 _ACEOF fi done if test "${ac_cv_header_gmpxx_h}" == "no" then as_fn_error "Need the gmp and gmpxx library; get them from http://www.swox.com/gmp/ and configure them with --enable-cxx. Also make sure to set CPPFLAGS if necessary." "$LINENO" 5 fi for ac_header in pcrecpp.h do : ac_fn_cxx_check_header_mongrel "$LINENO" "pcrecpp.h" "ac_cv_header_pcrecpp_h" "$ac_includes_default" if test "x$ac_cv_header_pcrecpp_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PCRECPP_H 1 _ACEOF fi done if test "${ac_cv_header_pcrecpp_h}" == "no" then as_fn_error "Need the pcrecpp library; get it from http://www.pcre.org . Make sure to set CPPFLAGS if necessary." "$LINENO" 5 fi if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_PKG_CONFIG+set}" = set; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_path_ac_pt_PKG_CONFIG+set}" = set; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 $as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } PKG_CONFIG="" fi fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sigc" >&5 $as_echo_n "checking for sigc... " >&6; } if test -n "$PKG_CONFIG"; then if test -n "$sigc_CFLAGS"; then pkg_cv_sigc_CFLAGS="$sigc_CFLAGS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sigc++-2.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "sigc++-2.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_sigc_CFLAGS=`$PKG_CONFIG --cflags "sigc++-2.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$sigc_LIBS"; then pkg_cv_sigc_LIBS="$sigc_LIBS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sigc++-2.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "sigc++-2.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_sigc_LIBS=`$PKG_CONFIG --libs "sigc++-2.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then sigc_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "sigc++-2.0"` else sigc_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "sigc++-2.0"` fi # Put the nasty error message in config.log where it belongs echo "$sigc_PKG_ERRORS" >&5 as_fn_error "Package requirements (sigc++-2.0) were not met: $sigc_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables sigc_CFLAGS and sigc_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " "$LINENO" 5 elif test $pkg_failed = untried; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables sigc_CFLAGS and sigc_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." "$LINENO" 5; } else sigc_CFLAGS=$pkg_cv_sigc_CFLAGS sigc_LIBS=$pkg_cv_sigc_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for modglue" >&5 $as_echo_n "checking for modglue... " >&6; } if test -n "$PKG_CONFIG"; then if test -n "$modglue_CFLAGS"; then pkg_cv_modglue_CFLAGS="$modglue_CFLAGS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"modglue\""; } >&5 ($PKG_CONFIG --exists --print-errors "modglue") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_modglue_CFLAGS=`$PKG_CONFIG --cflags "modglue" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$modglue_LIBS"; then pkg_cv_modglue_LIBS="$modglue_LIBS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"modglue\""; } >&5 ($PKG_CONFIG --exists --print-errors "modglue") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_modglue_LIBS=`$PKG_CONFIG --libs "modglue" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then modglue_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "modglue"` else modglue_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "modglue"` fi # Put the nasty error message in config.log where it belongs echo "$modglue_PKG_ERRORS" >&5 as_fn_error "Package requirements (modglue) were not met: $modglue_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables modglue_CFLAGS and modglue_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " "$LINENO" 5 elif test $pkg_failed = untried; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables modglue_CFLAGS and modglue_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." "$LINENO" 5; } else modglue_CFLAGS=$pkg_cv_modglue_CFLAGS modglue_LIBS=$pkg_cv_modglue_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : fi if test "$check_runtime_dependencies" == "yes" then # Extract the first word of "ptywrap", so it can be a program name with args. set dummy ptywrap; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_PTYWRAP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$PTYWRAP"; then ac_cv_prog_PTYWRAP="$PTYWRAP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_PTYWRAP="yes" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_PTYWRAP" && ac_cv_prog_PTYWRAP="no" fi fi PTYWRAP=$ac_cv_prog_PTYWRAP if test -n "$PTYWRAP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PTYWRAP" >&5 $as_echo "$PTYWRAP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "${PTYWRAP}" == "no" then as_fn_error "You have the modglue library, but the \"ptywrap\" tool which comes with it is not installed or executable." "$LINENO" 5 fi fi MAC_OS_X="" if test "`uname`" == "Darwin" then MAC_OS_X="1" echo "checking system type... Darwin" else echo "checking system type... Unix" fi echo -n "Checking whether to use -fnested-functions with ${CXX}... " echo "main() {};" > conftmp.c NESTED=-fnested-functions if ${CXX} -fnested-functions -c -o conftmp.o conftmp.c 1>/dev/null 2>&1 then echo " yes" else NESTED="" echo " no" fi rm -f conftmp.c conftmp.o { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build the GUI" >&5 $as_echo_n "checking whether to build the GUI... " >&6; } # Check whether --enable-gui was given. if test "${enable_gui+set}" = set; then : enableval=$enable_gui; else enable_gui=yes fi if test "$enable_gui" == "no" then echo "no" else echo "yes" pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sigc" >&5 $as_echo_n "checking for sigc... " >&6; } if test -n "$PKG_CONFIG"; then if test -n "$sigc_CFLAGS"; then pkg_cv_sigc_CFLAGS="$sigc_CFLAGS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sigc++-2.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "sigc++-2.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_sigc_CFLAGS=`$PKG_CONFIG --cflags "sigc++-2.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$sigc_LIBS"; then pkg_cv_sigc_LIBS="$sigc_LIBS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sigc++-2.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "sigc++-2.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_sigc_LIBS=`$PKG_CONFIG --libs "sigc++-2.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then sigc_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "sigc++-2.0"` else sigc_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "sigc++-2.0"` fi # Put the nasty error message in config.log where it belongs echo "$sigc_PKG_ERRORS" >&5 as_fn_error "Package requirements (sigc++-2.0) were not met: $sigc_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables sigc_CFLAGS and sigc_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " "$LINENO" 5 elif test $pkg_failed = untried; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables sigc_CFLAGS and sigc_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." "$LINENO" 5; } else sigc_CFLAGS=$pkg_cv_sigc_CFLAGS sigc_LIBS=$pkg_cv_sigc_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gtk" >&5 $as_echo_n "checking for gtk... " >&6; } if test -n "$PKG_CONFIG"; then if test -n "$gtk_CFLAGS"; then pkg_cv_gtk_CFLAGS="$gtk_CFLAGS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtk+-2.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_gtk_CFLAGS=`$PKG_CONFIG --cflags "gtk+-2.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$gtk_LIBS"; then pkg_cv_gtk_LIBS="$gtk_LIBS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtk+-2.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_gtk_LIBS=`$PKG_CONFIG --libs "gtk+-2.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then gtk_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "gtk+-2.0"` else gtk_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "gtk+-2.0"` fi # Put the nasty error message in config.log where it belongs echo "$gtk_PKG_ERRORS" >&5 as_fn_error "Package requirements (gtk+-2.0) were not met: $gtk_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables gtk_CFLAGS and gtk_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " "$LINENO" 5 elif test $pkg_failed = untried; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables gtk_CFLAGS and gtk_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." "$LINENO" 5; } else gtk_CFLAGS=$pkg_cv_gtk_CFLAGS gtk_LIBS=$pkg_cv_gtk_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pango" >&5 $as_echo_n "checking for pango... " >&6; } if test -n "$PKG_CONFIG"; then if test -n "$pango_CFLAGS"; then pkg_cv_pango_CFLAGS="$pango_CFLAGS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"pango\""; } >&5 ($PKG_CONFIG --exists --print-errors "pango") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_pango_CFLAGS=`$PKG_CONFIG --cflags "pango" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$pango_LIBS"; then pkg_cv_pango_LIBS="$pango_LIBS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"pango\""; } >&5 ($PKG_CONFIG --exists --print-errors "pango") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_pango_LIBS=`$PKG_CONFIG --libs "pango" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then pango_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "pango"` else pango_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "pango"` fi # Put the nasty error message in config.log where it belongs echo "$pango_PKG_ERRORS" >&5 as_fn_error "Package requirements (pango) were not met: $pango_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables pango_CFLAGS and pango_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " "$LINENO" 5 elif test $pkg_failed = untried; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables pango_CFLAGS and pango_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." "$LINENO" 5; } else pango_CFLAGS=$pkg_cv_pango_CFLAGS pango_LIBS=$pkg_cv_pango_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTKMM" >&5 $as_echo_n "checking for GTKMM... " >&6; } if test -n "$PKG_CONFIG"; then if test -n "$GTKMM_CFLAGS"; then pkg_cv_GTKMM_CFLAGS="$GTKMM_CFLAGS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtkmm-2.4 >= 2.12.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtkmm-2.4 >= 2.12.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GTKMM_CFLAGS=`$PKG_CONFIG --cflags "gtkmm-2.4 >= 2.12.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$GTKMM_LIBS"; then pkg_cv_GTKMM_LIBS="$GTKMM_LIBS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtkmm-2.4 >= 2.12.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtkmm-2.4 >= 2.12.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GTKMM_LIBS=`$PKG_CONFIG --libs "gtkmm-2.4 >= 2.12.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then GTKMM_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "gtkmm-2.4 >= 2.12.0"` else GTKMM_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "gtkmm-2.4 >= 2.12.0"` fi # Put the nasty error message in config.log where it belongs echo "$GTKMM_PKG_ERRORS" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTKMM" >&5 $as_echo_n "checking for GTKMM... " >&6; } if test -n "$PKG_CONFIG"; then if test -n "$GTKMM_CFLAGS"; then pkg_cv_GTKMM_CFLAGS="$GTKMM_CFLAGS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtkmm-2.4 >= 2.8.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtkmm-2.4 >= 2.8.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GTKMM_CFLAGS=`$PKG_CONFIG --cflags "gtkmm-2.4 >= 2.8.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$GTKMM_LIBS"; then pkg_cv_GTKMM_LIBS="$GTKMM_LIBS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtkmm-2.4 >= 2.8.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtkmm-2.4 >= 2.8.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GTKMM_LIBS=`$PKG_CONFIG --libs "gtkmm-2.4 >= 2.8.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then GTKMM_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "gtkmm-2.4 >= 2.8.0"` else GTKMM_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "gtkmm-2.4 >= 2.8.0"` fi # Put the nasty error message in config.log where it belongs echo "$GTKMM_PKG_ERRORS" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTKMM" >&5 $as_echo_n "checking for GTKMM... " >&6; } if test -n "$PKG_CONFIG"; then if test -n "$GTKMM_CFLAGS"; then pkg_cv_GTKMM_CFLAGS="$GTKMM_CFLAGS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtkmm-2.4 >= 2.6.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtkmm-2.4 >= 2.6.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GTKMM_CFLAGS=`$PKG_CONFIG --cflags "gtkmm-2.4 >= 2.6.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$GTKMM_LIBS"; then pkg_cv_GTKMM_LIBS="$GTKMM_LIBS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtkmm-2.4 >= 2.6.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtkmm-2.4 >= 2.6.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GTKMM_LIBS=`$PKG_CONFIG --libs "gtkmm-2.4 >= 2.6.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then GTKMM_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "gtkmm-2.4 >= 2.6.0"` else GTKMM_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "gtkmm-2.4 >= 2.6.0"` fi # Put the nasty error message in config.log where it belongs echo "$GTKMM_PKG_ERRORS" >&5 as_fn_error "Package requirements (gtkmm-2.4 >= 2.6.0) were not met: $GTKMM_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables GTKMM_CFLAGS and GTKMM_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " "$LINENO" 5 elif test $pkg_failed = untried; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables GTKMM_CFLAGS and GTKMM_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." "$LINENO" 5; } else GTKMM_CFLAGS=$pkg_cv_GTKMM_CFLAGS GTKMM_LIBS=$pkg_cv_GTKMM_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define GTKMM_VER 26" >>confdefs.h fi elif test $pkg_failed = untried; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTKMM" >&5 $as_echo_n "checking for GTKMM... " >&6; } if test -n "$PKG_CONFIG"; then if test -n "$GTKMM_CFLAGS"; then pkg_cv_GTKMM_CFLAGS="$GTKMM_CFLAGS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtkmm-2.4 >= 2.6.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtkmm-2.4 >= 2.6.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GTKMM_CFLAGS=`$PKG_CONFIG --cflags "gtkmm-2.4 >= 2.6.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$GTKMM_LIBS"; then pkg_cv_GTKMM_LIBS="$GTKMM_LIBS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtkmm-2.4 >= 2.6.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtkmm-2.4 >= 2.6.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GTKMM_LIBS=`$PKG_CONFIG --libs "gtkmm-2.4 >= 2.6.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then GTKMM_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "gtkmm-2.4 >= 2.6.0"` else GTKMM_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "gtkmm-2.4 >= 2.6.0"` fi # Put the nasty error message in config.log where it belongs echo "$GTKMM_PKG_ERRORS" >&5 as_fn_error "Package requirements (gtkmm-2.4 >= 2.6.0) were not met: $GTKMM_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables GTKMM_CFLAGS and GTKMM_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " "$LINENO" 5 elif test $pkg_failed = untried; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables GTKMM_CFLAGS and GTKMM_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." "$LINENO" 5; } else GTKMM_CFLAGS=$pkg_cv_GTKMM_CFLAGS GTKMM_LIBS=$pkg_cv_GTKMM_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define GTKMM_VER 26" >>confdefs.h fi else GTKMM_CFLAGS=$pkg_cv_GTKMM_CFLAGS GTKMM_LIBS=$pkg_cv_GTKMM_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define GTKMM_VER 28" >>confdefs.h fi elif test $pkg_failed = untried; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTKMM" >&5 $as_echo_n "checking for GTKMM... " >&6; } if test -n "$PKG_CONFIG"; then if test -n "$GTKMM_CFLAGS"; then pkg_cv_GTKMM_CFLAGS="$GTKMM_CFLAGS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtkmm-2.4 >= 2.8.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtkmm-2.4 >= 2.8.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GTKMM_CFLAGS=`$PKG_CONFIG --cflags "gtkmm-2.4 >= 2.8.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$GTKMM_LIBS"; then pkg_cv_GTKMM_LIBS="$GTKMM_LIBS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtkmm-2.4 >= 2.8.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtkmm-2.4 >= 2.8.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GTKMM_LIBS=`$PKG_CONFIG --libs "gtkmm-2.4 >= 2.8.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then GTKMM_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "gtkmm-2.4 >= 2.8.0"` else GTKMM_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "gtkmm-2.4 >= 2.8.0"` fi # Put the nasty error message in config.log where it belongs echo "$GTKMM_PKG_ERRORS" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTKMM" >&5 $as_echo_n "checking for GTKMM... " >&6; } if test -n "$PKG_CONFIG"; then if test -n "$GTKMM_CFLAGS"; then pkg_cv_GTKMM_CFLAGS="$GTKMM_CFLAGS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtkmm-2.4 >= 2.6.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtkmm-2.4 >= 2.6.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GTKMM_CFLAGS=`$PKG_CONFIG --cflags "gtkmm-2.4 >= 2.6.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$GTKMM_LIBS"; then pkg_cv_GTKMM_LIBS="$GTKMM_LIBS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtkmm-2.4 >= 2.6.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtkmm-2.4 >= 2.6.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GTKMM_LIBS=`$PKG_CONFIG --libs "gtkmm-2.4 >= 2.6.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then GTKMM_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "gtkmm-2.4 >= 2.6.0"` else GTKMM_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "gtkmm-2.4 >= 2.6.0"` fi # Put the nasty error message in config.log where it belongs echo "$GTKMM_PKG_ERRORS" >&5 as_fn_error "Package requirements (gtkmm-2.4 >= 2.6.0) were not met: $GTKMM_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables GTKMM_CFLAGS and GTKMM_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " "$LINENO" 5 elif test $pkg_failed = untried; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables GTKMM_CFLAGS and GTKMM_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." "$LINENO" 5; } else GTKMM_CFLAGS=$pkg_cv_GTKMM_CFLAGS GTKMM_LIBS=$pkg_cv_GTKMM_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define GTKMM_VER 26" >>confdefs.h fi elif test $pkg_failed = untried; then pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTKMM" >&5 $as_echo_n "checking for GTKMM... " >&6; } if test -n "$PKG_CONFIG"; then if test -n "$GTKMM_CFLAGS"; then pkg_cv_GTKMM_CFLAGS="$GTKMM_CFLAGS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtkmm-2.4 >= 2.6.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtkmm-2.4 >= 2.6.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GTKMM_CFLAGS=`$PKG_CONFIG --cflags "gtkmm-2.4 >= 2.6.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$GTKMM_LIBS"; then pkg_cv_GTKMM_LIBS="$GTKMM_LIBS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtkmm-2.4 >= 2.6.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "gtkmm-2.4 >= 2.6.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GTKMM_LIBS=`$PKG_CONFIG --libs "gtkmm-2.4 >= 2.6.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then GTKMM_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "gtkmm-2.4 >= 2.6.0"` else GTKMM_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "gtkmm-2.4 >= 2.6.0"` fi # Put the nasty error message in config.log where it belongs echo "$GTKMM_PKG_ERRORS" >&5 as_fn_error "Package requirements (gtkmm-2.4 >= 2.6.0) were not met: $GTKMM_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables GTKMM_CFLAGS and GTKMM_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " "$LINENO" 5 elif test $pkg_failed = untried; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables GTKMM_CFLAGS and GTKMM_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." "$LINENO" 5; } else GTKMM_CFLAGS=$pkg_cv_GTKMM_CFLAGS GTKMM_LIBS=$pkg_cv_GTKMM_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define GTKMM_VER 26" >>confdefs.h fi else GTKMM_CFLAGS=$pkg_cv_GTKMM_CFLAGS GTKMM_LIBS=$pkg_cv_GTKMM_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define GTKMM_VER 28" >>confdefs.h fi else GTKMM_CFLAGS=$pkg_cv_GTKMM_CFLAGS GTKMM_LIBS=$pkg_cv_GTKMM_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define GTKMM_VER 212" >>confdefs.h fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GLIBMM" >&5 $as_echo_n "checking for GLIBMM... " >&6; } if test -n "$PKG_CONFIG"; then if test -n "$GLIBMM_CFLAGS"; then pkg_cv_GLIBMM_CFLAGS="$GLIBMM_CFLAGS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glibmm-2.4 >= 2.16.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "glibmm-2.4 >= 2.16.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GLIBMM_CFLAGS=`$PKG_CONFIG --cflags "glibmm-2.4 >= 2.16.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$GLIBMM_LIBS"; then pkg_cv_GLIBMM_LIBS="$GLIBMM_LIBS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glibmm-2.4 >= 2.16.0\""; } >&5 ($PKG_CONFIG --exists --print-errors "glibmm-2.4 >= 2.16.0") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GLIBMM_LIBS=`$PKG_CONFIG --libs "glibmm-2.4 >= 2.16.0" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then GLIBMM_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "glibmm-2.4 >= 2.16.0"` else GLIBMM_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "glibmm-2.4 >= 2.16.0"` fi # Put the nasty error message in config.log where it belongs echo "$GLIBMM_PKG_ERRORS" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "#define GLIBMM_VER old" >>confdefs.h echo "Using old glibmm" elif test $pkg_failed = untried; then $as_echo "#define GLIBMM_VER old" >>confdefs.h echo "Using old glibmm" else GLIBMM_CFLAGS=$pkg_cv_GLIBMM_CFLAGS GLIBMM_LIBS=$pkg_cv_GLIBMM_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } $as_echo "#define GLIBMM_VER 216" >>confdefs.h fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pangomm" >&5 $as_echo_n "checking for pangomm... " >&6; } if test -n "$PKG_CONFIG"; then if test -n "$pangomm_CFLAGS"; then pkg_cv_pangomm_CFLAGS="$pangomm_CFLAGS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"pangomm-1.4\""; } >&5 ($PKG_CONFIG --exists --print-errors "pangomm-1.4") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_pangomm_CFLAGS=`$PKG_CONFIG --cflags "pangomm-1.4" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test -n "$PKG_CONFIG"; then if test -n "$pangomm_LIBS"; then pkg_cv_pangomm_LIBS="$pangomm_LIBS" else if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"pangomm-1.4\""; } >&5 ($PKG_CONFIG --exists --print-errors "pangomm-1.4") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_pangomm_LIBS=`$PKG_CONFIG --libs "pangomm-1.4" 2>/dev/null` else pkg_failed=yes fi fi else pkg_failed=untried fi if test $pkg_failed = yes; then if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then pangomm_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "pangomm-1.4"` else pangomm_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "pangomm-1.4"` fi # Put the nasty error message in config.log where it belongs echo "$pangomm_PKG_ERRORS" >&5 as_fn_error "Package requirements (pangomm-1.4) were not met: $pangomm_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. Alternatively, you may set the environment variables pangomm_CFLAGS and pangomm_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. " "$LINENO" 5 elif test $pkg_failed = untried; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. Alternatively, you may set the environment variables pangomm_CFLAGS and pangomm_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details. To get pkg-config, see . See \`config.log' for more details." "$LINENO" 5; } else pangomm_CFLAGS=$pkg_cv_pangomm_CFLAGS pangomm_LIBS=$pkg_cv_pangomm_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } : fi if test "$check_runtime_dependencies" == "yes" then # Extract the first word of "dvipng", so it can be a program name with args. set dummy dvipng; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_DVIPNG+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$DVIPNG"; then ac_cv_prog_DVIPNG="$DVIPNG" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_DVIPNG="yes" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_DVIPNG" && ac_cv_prog_DVIPNG="no" fi fi DVIPNG=$ac_cv_prog_DVIPNG if test -n "$DVIPNG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DVIPNG" >&5 $as_echo "$DVIPNG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "${DVIPNG}" == "no" then as_fn_error "Need the dvipng program; get it from http://sourceforge.net/projects/dvipng/ ." "$LINENO" 5 fi # Extract the first word of "latex", so it can be a program name with args. set dummy latex; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_LATEX+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$LATEX"; then ac_cv_prog_LATEX="$LATEX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_LATEX="yes" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_LATEX" && ac_cv_prog_LATEX="no" fi fi LATEX=$ac_cv_prog_LATEX if test -n "$LATEX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LATEX" >&5 $as_echo "$LATEX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "${LATEX}" == "no" then as_fn_error "Need a working LaTeX installation." "$LINENO" 5 fi printf '\\nonstopmode\\documentclass{article}\\usepackage{breqn}\\begin{document}\\begin{dmath*}x^2\\end{dmath*}\\end{document}\n' > conftmp.tex printf "checking for breqn package..." if latex conftmp.tex > /dev/null 2>&1 then echo " yes" else echo " no" as_fn_error "Need the breqn LaTeX package; get it from ftp://ftp.ams.org/pub/tex/ ." "$LINENO" 5 fi rm -f conftmp.tex conftmp.log conftmp.dvi conftmp.aux fi fi ac_config_files="$ac_config_files Makefile src/Makefile src/modules/Makefile tests/Makefile gui/Makefile doc/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then test "x$cache_file" != "x/dev/null" && { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} cat confcache >$cache_file else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error ERROR [LINENO LOG_FD] # --------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with status $?, using 1 if that was 0. as_fn_error () { as_status=$?; test $as_status -eq 0 && as_status=1 if test "$3"; then as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 fi $as_echo "$as_me: error: $1" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.65. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.65, with options \\"\$ac_cs_config\\" Copyright (C) 2009 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "src/config.h") CONFIG_HEADERS="$CONFIG_HEADERS src/config.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; "src/modules/Makefile") CONFIG_FILES="$CONFIG_FILES src/modules/Makefile" ;; "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;; "gui/Makefile") CONFIG_FILES="$CONFIG_FILES gui/Makefile" ;; "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= trap 'exit_status=$? { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ || as_fn_error "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=/{ s/:*\$(srcdir):*/:/ s/:*\${srcdir}:*/:/ s/:*@srcdir@:*/:/ s/^\([^=]*=[ ]*\):*/\1/ s/:*$// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_t=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_t"; then break elif $ac_last_try; then as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$tmp/stdin" \ || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ || as_fn_error "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined." >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined." >&2;} rm -f "$tmp/stdin" case $ac_file in -) cat "$tmp/out" && rm -f "$tmp/out";; *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; esac \ || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" } >"$tmp/config.h" \ || as_fn_error "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$tmp/config.h" "$ac_file" \ || as_fn_error "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit $? fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi cadabra-1.39/configure.in000066400000000000000000000206471234107666300153550ustar00rootroot00000000000000 AC_INIT(src/storage.cc) AC_PROG_CC AC_PROG_CXX AC_PROG_LN_S AC_PROG_MAKE_SET AC_PROG_INSTALL AC_PREFIX_DEFAULT(/usr/local) AC_SUBST(install_flags) AC_CONFIG_HEADER(src/config.h) AC_LANG(C++) # Figure out how to turn on compiler warnings. AC_DEFUN([AX_CFLAGS_WARN_ALL],[dnl AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_warn_all])dnl AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum warnings], VAR,[VAR="no, unknown" AC_LANG_SAVE AC_LANG_C ac_save_[]FLAGS="$[]FLAGS" for ac_arg dnl in "-pedantic % -Wall" dnl GCC "-xstrconst % -v" dnl Solaris C "-std1 % -verbose -w0 -warnprotos" dnl Digital Unix "-qlanglvl=ansi % -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX "-ansi -ansiE % -fullwarn" dnl IRIX "+ESlit % +w1" dnl HP-UX C "-Xc % -pvctl[,]fullmsg" dnl NEC SX-5 (Super-UX 10) "-h conform % -h msglevel 2" dnl Cray C (Unicos) # do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` AC_TRY_COMPILE([],[return 0;], [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) done FLAGS="$ac_save_[]FLAGS" AC_LANG_RESTORE ]) case ".$VAR" in .ok|.ok,*) m4_ifvaln($3,$3) ;; .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[ AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"]) m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;; *) m4_ifvaln($3,$3,[ if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" fi ]) ;; esac AS_VAR_POPDEF([VAR])dnl AS_VAR_POPDEF([FLAGS])dnl ]) dnl the only difference - the LANG selection... and the default FLAGS AC_DEFUN([AX_CXXFLAGS_WARN_ALL],[dnl AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_warn_all])dnl AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum warnings], VAR,[VAR="no, unknown" AC_LANG_SAVE AC_LANG_CPLUSPLUS ac_save_[]FLAGS="$[]FLAGS" for ac_arg dnl in "-pedantic % -Wall" dnl GCC "-xstrconst % -v" dnl Solaris C "-std1 % -verbose -w0 -warnprotos" dnl Digital Unix "-qlanglvl=ansi % -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX "-ansi -ansiE % -fullwarn" dnl IRIX "+ESlit % +w1" dnl HP-UX C "-Xc % -pvctl[,]fullmsg" dnl NEC SX-5 (Super-UX 10) "-h conform % -h msglevel 2" dnl Cray C (Unicos) # do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` AC_TRY_COMPILE([],[return 0;], [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) done FLAGS="$ac_save_[]FLAGS" AC_LANG_RESTORE ]) case ".$VAR" in .ok|.ok,*) m4_ifvaln($3,$3) ;; .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[ AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"]) m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;; *) m4_ifvaln($3,$3,[ if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" fi ]) ;; esac AS_VAR_POPDEF([VAR])dnl AS_VAR_POPDEF([FLAGS])dnl ]) AX_CFLAGS_WARN_ALL dnl EXPECTPATH="" dnl AC_CHECK_HEADER(expect.h, AC_DEFINE(EXPECTPATH, )) dnl if test "$ac_cv_header_expect_h" != "yes" dnl then AC_CHECK_HEADER(tcl8.4/expect.h, AC_DEFINE(EXPECTPATH, )) dnl if test "$ac_cv_header_tcl8_4_expect_h" != "yes" dnl then AC_MSG_ERROR([Need the expect library; get it from http://expect.nist.gov/ .]) dnl fi dnl fi AC_ARG_ENABLE([runtime-dependency-check], [AS_HELP_STRING([--enable-runtime-dependency-check], [Enable check for runtime dependencies (default is yes)])], , check_runtime_dependencies=yes) if test "$check_runtime_dependencies" == "yes" then AC_CHECK_PROG(LIE, lie, yes, no) if test "${LIE}" == "no" then AC_MSG_ERROR([Need the LiE program; get it from http://young.sp2mi.univ-poitiers.fr/~marc/LiE/ .]) fi fi AC_CHECK_HEADERS(pcre.h) if test "${ac_cv_header_pcre_h}" == "no" then AC_MSG_ERROR([Need the pcre library; get it from http://www.pcre.org/ . Make sure to set CPPFLAGS if necessary.]) fi AC_CHECK_HEADERS(gmpxx.h) if test "${ac_cv_header_gmpxx_h}" == "no" then AC_MSG_ERROR([Need the gmp and gmpxx library; get them from http://www.swox.com/gmp/ and configure them with --enable-cxx. Also make sure to set CPPFLAGS if necessary.]) fi dnl AC_CHECK_HEADERS(pcre++.h) AC_CHECK_HEADERS(pcrecpp.h) dnl if test "${ac_cv_header_pcrecpp_h}" == "no" -a "${ac_cv_header_pcrepp_h}" == "no" if test "${ac_cv_header_pcrecpp_h}" == "no" then AC_MSG_ERROR([Need the pcrecpp library; get it from http://www.pcre.org . Make sure to set CPPFLAGS if necessary.]) fi dnl if test "${ac_cv_header_pcre++_h}" == "no" dnl then pcrecpp=yes dnl else pcrecpp=no dnl fi PKG_CHECK_MODULES([sigc], [sigc++-2.0]) PKG_CHECK_MODULES([modglue], [modglue]) if test "$check_runtime_dependencies" == "yes" then AC_CHECK_PROG(PTYWRAP, ptywrap, yes, no) if test "${PTYWRAP}" == "no" then AC_MSG_ERROR([You have the modglue library, but the "ptywrap" tool which comes with it is not installed or executable.]) fi fi MAC_OS_X="" if test "`uname`" == "Darwin" then MAC_OS_X="1" echo "checking system type... Darwin" else echo "checking system type... Unix" fi echo -n "Checking whether to use -fnested-functions with ${CXX}... " echo "main() {};" > conftmp.c NESTED=-fnested-functions if ${CXX} -fnested-functions -c -o conftmp.o conftmp.c 1>/dev/null 2>&1 then echo " yes" else NESTED="" echo " no" fi rm -f conftmp.c conftmp.o dnl Optional configuration of the experimental GUI AC_MSG_CHECKING([whether to build the GUI]) AC_ARG_ENABLE([gui], [AS_HELP_STRING([--enable-gui], [Enable building of the graphical front-end (default is yes)])], , enable_gui=yes) if test "$enable_gui" == "no" then echo "no" else echo "yes" PKG_CHECK_MODULES([sigc], [sigc++-2.0]) PKG_CHECK_MODULES([gtk], [gtk+-2.0]) PKG_CHECK_MODULES([pango], [pango]) PKG_CHECK_MODULES(GTKMM, gtkmm-2.4 >= 2.12.0, [AC_DEFINE([GTKMM_VER],212)], [PKG_CHECK_MODULES(GTKMM, gtkmm-2.4 >= 2.8.0, [AC_DEFINE([GTKMM_VER],28)], [PKG_CHECK_MODULES(GTKMM, gtkmm-2.4 >= 2.6.0, AC_DEFINE([GTKMM_VER],26))])]) PKG_CHECK_MODULES(GLIBMM, glibmm-2.4 >= 2.16.0, [AC_DEFINE([GLIBMM_VER],216)], [AC_DEFINE([GLIBMM_VER],old) echo "Using old glibmm"]) dnl PKG_CHECK_MODULES([gtkmm], [gtkmm-2.4]) dnl if test "x`pkg-config --modversion gtkmm-2.4 | grep 2.8`" == "x" ; then dnl AC_DEFINE([GTKMM_GEQ_28], 0, [Defined if Gtkmm's version is 2.8 or greater]) dnl echo "checking for gtkmm version... < 2.8" dnl else dnl AC_DEFINE([GTKMM_GEQ_28], 1, [Defined if Gtkmm's version is 2.8 or greater]) dnl echo "checking for gtkmm version... >= 2.8" dnl fi PKG_CHECK_MODULES([pangomm], [pangomm-1.4]) if test "$check_runtime_dependencies" == "yes" then AC_CHECK_PROG(DVIPNG, dvipng, yes, no) if test "${DVIPNG}" == "no" then AC_MSG_ERROR([Need the dvipng program; get it from http://sourceforge.net/projects/dvipng/ .]) fi AC_CHECK_PROG(LATEX, latex, yes, no) if test "${LATEX}" == "no" then AC_MSG_ERROR([Need a working LaTeX installation.]) fi printf '\\nonstopmode\\documentclass{article}\\usepackage{breqn}\\begin{document}\\begin{dmath*}x^2\\end{dmath*}\\end{document}\n' > conftmp.tex printf "checking for breqn package..." if latex conftmp.tex > /dev/null 2>&1 then echo " yes" else echo " no" AC_MSG_ERROR([Need the breqn LaTeX package; get it from ftp://ftp.ams.org/pub/tex/ .]) fi rm -f conftmp.tex conftmp.log conftmp.dvi conftmp.aux fi fi AC_SUBST([enable_gui]) AC_SUBST([MAC_OS_X]) AC_SUBST([pcrecpp]) AC_SUBST([NESTED]) AC_SUBST([GTKMM_VER]) AC_SUBST([GLIBMM_VER]) dnl The output files AC_OUTPUT( Makefile src/Makefile src/modules/Makefile tests/Makefile gui/Makefile doc/Makefile ) cadabra-1.39/doc/000077500000000000000000000000001234107666300136005ustar00rootroot00000000000000cadabra-1.39/doc/ChangeLog000066400000000000000000000246371234107666300153660ustar00rootroot000000000000002009-05-05 Kasper Peeters * Released 2.65 * Added skip_children(bool), fixed post-increment/decrement operators to not refer to 'n' anymore. 2009-04-03 Kasper Peeters * Added a sibling member for quick access to the n-th sibling (thanks to Adam Connell for sending the patch). 2009-03-06 Kasper Peeters * Fixed an old bug in compare_nodes (pointed out to me in 2005 but never fixed properly...) 2008-08-28 Kasper Peeters * Released 2.62 * Changed the behaviour of max_depth() so that it returns -1 for an empty tree, instead of bailing out with an error (strictly speaking max_depth should be undefined...). 2008-08-26 Kasper Peeters * Released 2.61 * Fixed a bug in max_depth() which would fail on trees with more than one head node (thanks to Marc Noirot for pointing this out). 2008-08-23 Kasper Peeters * Released 2.60 * Fixed several problems with fixed_depth iterators: iterating beyond the top node now disabled and operator-- fixed. 2008-07-25 Kasper Peeters * Made 'child()' static. 2008-07-20 Kasper Peeters * Released 2.54 * Changed size() members to return size_t instead of unsigned int. * Changed behaviour of operator++ for leaf_iterator so that it can be used in situations where new leaves get added during iteration. 2008-06-30 Kasper Peeters * Released 2.52 * Made depth member function static so it can be used independent of an actual tree, and added a version with two iterators to measure depths relative to a different node. 2008-02-28 Kasper Peeters * Released 2.51 * Added a top node to leaf_iterators, so that they can be instructed to iterate only over the leaves of a given node. 2007-10-19 Kasper Peeters * Released 2.4. 2007-10-18 Kasper Peeters * Added max_depth() members. * Fixed a bug in begin_fixed() which would fail on A / \ B C / \ D E / \ F G when asked for the first node at depth 3 from 'A' (since it failed to go back up the tree from 'D'). 2007-08-21 Kasper Peeters * Released 2.31. * Added GPL version 3 licensing as an option. 2007-01-19 Kasper Peeters * Fixed a bug in "replace" which appeared when trying to replace a head node (it tried to access the parent). 2006-11-29 Kasper Peeters * Release 2.3. Fixed a bug in number_of_siblings which only counted siblings in one direction (thanks to Fanzhe Cui for pointing this out). 2006-08-20 Kasper Peeters * Released 2.2. * Added operator== and operator!= for fixed_depth_iterator. 2006-08-07 Kasper Peeters * Released 2.1. * Added leaf iterators, code contributed by Peter Wienemann. * Fixed a bug in is_valid (thanks to Antonio Morillas). 1.131. 2006-07-19 Kasper Peeters * Fixed bugs in move_before and move_after which would show up when the node was already in the right place. 1.130. 2006-03-02 Kasper Peeters * Added the "wrap" member function. 2006-03-01 Kasper Peeters * Added a simple queue-based breadth-first iterator. 2006-01-31 Kasper Peeters * Fixed move_before to work when the target is a sibling_iterator pointing to the end of a range of siblings. 2005-11-20 Kasper Peeters * Added move_after, which for some mysterious reason was missing. Thanks to Dennis Jones for pointing this out. * Fixed a bug in operator++ for post_order iterators (skip_children could remain set if no next sibling present). Thanks to Ohad for pointing out the bug. 2005-10-12 Kasper Peeters * Fixed a bug in the 'sort' member which takes a Comparator function object (thanks to Robin Taylor for the patch). 2005-09-14 Kasper Peeters * Doxygen documentation added, plus a new web page. 2004-11-05 Kasper Peeters * Fixed a bug which shows up when inserting nodes at the top of the tree (thanks to Matthias Bernt for pointing me to this one). 2004-07-21 Kasper Peeters * Fixed kp::destructor -> destructor. * Moved body of 'compare_nodes::operator()' into the class declaration in order to satisfy buggy Borland compilers (and stop regular email messages about this problem). * Fixed a completely buggy number_of_siblings() (thanks to Caleb Epstein for the patch). 2004-02-04 Kasper Peeters * Released 1.106 * Fixed a bug in insert(sibling_iterator, const T&) (thanks to Maxim Yegorushkin for the patch). 2003-11-21 Kasper Peeters * Put some things in a namespace to avoid clashes with other libraries. 2003-10-13 Kasper Peeters * Released 1.102. * Fixed return type of postincrement/decrement operators (thanks to Yevhen Tymokhin for pointing this out). 2003-09-18 Kasper Peeters * Fixes for standard compliance, as required to compile with gcc 3.4 and later. 2003-08-12 Kasper Peeters * Added 'empty' member (patch by Michael Vogt). 2003-08-01 * Released 1.95 * Fixed two bugs in sort (which were corrupting the tree); thanks to Michael Vogt for informing me about the problem. 2003-07-17 * Added a hack to enable compilation with STLport. 2003-07-11 * Released 1.90 * Added postfix increment and decrement operators; thanks to Claudio Andreatta for sending the patch. * Fixed a bug in reparent(iter pos, iter from). Thanks to Claudio Andreatta for fixing this. 2003-06-25 Kasper Peeters * Many bug fixes for fixed depth iterators, thanks to Ruben Niederhagen for pointing out several problems (a few still exist, see the 'TODO' part of tree.hh). 2003-04-17 Kasper Peeters * Released 1.85 * Corrected return type of operator++ and friends. * Added preliminary support for 'fixed_depth_iterator' to iterate over children at a given level. Not quite finished yet, sorry. 2003-03-24 Kasper Peeters * Released 1.83 * Changed return type of 'child' member function to be a sibling iterator instead of a reference to the actual node (sorry for the incompatibility with previous versions). Change also propagated to tree_msvc.hh. 2003-02-07 * Released 1.80 * Fixed another bug in sort (thanks to Tony Cook for fixing this bug). 2003-01-29 Kasper Peeters * Released 1.78. * Fixed a bug in sort, which resulted in a corrupt tree (thanks to Michael Vogt for fixing this bug). 2003-01-07 Kasper Peeters * Released 1.75 and msvc version 1.72 * Fixed a wrongly specialised 'insert' method for sibling_iterators (thanks to Tony Cook for pointing this out). 2002-11-15 Kasper Peeters * Released 1.72 * Fixed a bug in 'index' when called on nodes at the top level of the tree (thanks to David Zajic for the bug report). Be warned that the top level is a bit special at the moment; the end sibling_iterator is ill-defined for siblings there (to be fixed in a future version). 2002-10-31 Kasper Peeters * Released 1.70. * Finished the merge algorithm, updated the documentation with examples about its use, and added a test-case to the test_tree.cc program. * Fixed a bug in pre_order_iterator::operator--. 2002-10-20 Kasper Peeters * Released 1.66. 2002-10-15 Kasper Peeters * Code for post_order_iterator implemented. 2002-10-13 Kasper Peeters * Rewrote large parts of the code to allow for multiple iterator types, such as pre_order_iterator (which was the previous iterator type), post_order_iterator and so on. This required small changes to the interface, the most visible one being - insert(iterator, iterator) for the insertion of a subtree is now called insert_subtree(iterator, iterator). Apologies if this breaks your code. 2002-10-11 Kasper Peeters * Removed '(void)' type declarations in favour of the C++ standard empty brackets '()'. 2002-10-10 Kasper Peeters * Added 'index' in response to a discussion on the Boost mailing list. 2002-10-03 Kasper Peeters * reparent(iterator,sibling_iterator,sibling_iterator) now accepts an empty range, in which case it does nothing (request by Jos de Laender). * Fixed a bug in the iterator(sibling_iterator) constructor (thanks to Jos de Laender for pointing this out). 2002-09-04 Kasper Peeters * Fixed a bug in insert_after (thanks to Carl Blanchette for the patch). 2002-08-29 Kasper Peeters * The problem in test_tree of the previous item was actually do to tree::end(iterator) returning the end of the tree, not the end of the current sibling list. Fixed now, released 1.55. 2002-08-26 Kasper Peeters * Released 1.54. * Printing a single-node tree in test_tree would result in a segfault; more robust now (thanks to Yutaka Sato for the bug report). 2002-05-07 Kasper Peeters * Fixed a bug in "sort" which would remove duplicate nodes altogether. 2002-03-24 Kasper Peeters * Added "append_child" without child argument, to add empty child node. 2002-05-04 Kasper Peeters * Released 1.45. * Removed restriction of having only a single node at the top of the tree (associated with this, the top nodes should now be inserted with "insert", not with "append_child"). * Fixes for ISO compatibility (now works with gcc-3.1). Thanks to Olivier Verdier. cadabra-1.39/doc/Makefile000066400000000000000000000002071234107666300152370ustar00rootroot00000000000000 .PHONY: doxy all: doxy doxy: doxygen doxygen_cadabra.config distclean: rm -Rf doxygen algorithms/*~ properties/*~ reserved/*~ *~ cadabra-1.39/doc/Makefile.in000066400000000000000000000002071234107666300156440ustar00rootroot00000000000000 .PHONY: doxy all: doxy doxy: doxygen doxygen_cadabra.config distclean: rm -Rf doxygen algorithms/*~ properties/*~ reserved/*~ *~ cadabra-1.39/doc/algorithms/000077500000000000000000000000001234107666300157515ustar00rootroot00000000000000cadabra-1.39/doc/algorithms/acanonicalorder.tex000066400000000000000000000015321234107666300216200ustar00rootroot00000000000000\cdbalgorithm{acanonicalorder}{} Orders the indicated objects in the expression in canonical order, taking care of permutation signs. On a simple product of objects it works as a partial product sort for anti-commuting objects, \begin{screen}{1,2} C B E D F A ; @acanonicalorder!(%)(A, B, E, F); (-1) C A B D E F; \end{screen} It can, however, also be used to sort indices. Thereby, it facilitates imposing index symmetry on a tensor with open indices, as the following example illustrates. \begin{screen}{1,2} A^{m n p} B^{q r} + A^{q m} B^{n p r}; @acanonicalorder!(%)( ^{m}, ^{n}, ^{p}, ^{r}, ^{q} ); - A^{m n p} B^{r q} + A^{m n} B^{p r q}; \end{screen} A similar type of canonical ordering but without the permutation signs is provided for by \subscommand{canonicalorder}. ~ \cdbseealgo{canonicalorder} \cdbseealgo{prodsort} \cdbseealgo{canonicalise} cadabra-1.39/doc/algorithms/algorithms.tex000066400000000000000000000004401234107666300206420ustar00rootroot00000000000000\cdbalgorithm{algorithms}{} Display a list of all available algorithms. \begin{screen}{1} @algorithms; @ @acanonicalorder @all_contractions ... \end{screen} This list is also available in the graphical notebook interface from the Help menu. \cdbseealgo{properties} \cdbseealgo{timing} cadabra-1.39/doc/algorithms/all_contractions.tex000066400000000000000000000015241234107666300220330ustar00rootroot00000000000000\cdbalgorithm{all\_contractions}{} Construct all full contractions of the given tensors, taking into account mono-term symmetries. Example, \begin{screen}{1,2,3,4,5} A_{m n}::Symmetric. A_{m n}::Traceless. {m,n,p,q,r,s,t,u}::Indices(vector). {m,n,p,q,r,s,t,u}::Integer(0..9). obj14:= A_{m n} A_{p q} A_{r s} A_{t u}; @all_contractions(%){2}; A_{m n} A_{m n} A_{p q} A_{p q} + A_{m n} A_{m p} A_{n q} A_{p q}; \end{screen} This command is not entirely correct at the moment: it determines the total number of singlets correctly, but does not generate parity-odd contractions (the ones involving an epsilon tensor). It also does not know about dimension-dependent identities. If this is a problem for your application, contact the author for an experimental version of cadabra. \cdbseeprop{Symmetric} \cdbseeprop{Traceless} \cdbseealgo{canonicalise} cadabra-1.39/doc/algorithms/amnesia.tex000066400000000000000000000010611234107666300201060ustar00rootroot00000000000000\cdbalgorithm{amnesia}{} Forget the history of the indicated expression, that is, remove all previous forms of the expression from memory. \begin{screen}{1,2,4,5} A (B + C); @distribute!(%); A B + A C; @amnesia(%); @pop(%); @pop: not applicable. \end{screen} This is mainly useful to purge extremely long intermediate expressions from memory, while still retaining the option to use the expression history for other expressions (instead of switching expression histories off altogether with \subsprop{KeepHistory}). \cdbseealgo{pop} \cdbseeprop{KeepHistory} cadabra-1.39/doc/algorithms/assert.tex000066400000000000000000000006271234107666300200010ustar00rootroot00000000000000\cdbalgorithm{assert}{} Checks whether the indicated expression equals zero. If not, the program will be terminated. This command is used e.g.~in the test suite. \begin{screen}{1,2} 1 - B B**(-1); @collect_factors!(%); @collect_terms!(%); @assert(%); Assert check passed. \end{screen} If the expression is not zero an error message will be produced, and the program will be terminated. \cdbseealgo{tree} cadabra-1.39/doc/algorithms/asym.tex000066400000000000000000000014501234107666300174440ustar00rootroot00000000000000\cdbalgorithm{asym}{} Anti-symmetrise a product or tensor in the indicated objects. This works both with normal objects, as in \begin{screen}{1,2} A B C; @asym!(%){A,B,C}; 1/6 A B C - 1/6 A C B - 1/6 B A C + 1/6 B C A + 1/6 C A B - 1/6 C B A; \end{screen} as well as with indices. When used with indices, remember to also indicate whether you want to symmetrise upper or lower indices, as in the example below. \begin{screen}{1,2} A_{m n} B_{p}; @asym!(%){ _{m}, _{n}, _{p} }; 1/6 A_{m n} B_{p} - 1/6 A_{m p} B_{n} - 1/6 A_{n m} B_{p} + 1/6 A_{n p} B_{m} + 1/6 A_{p m} B_{n} - 1/6 A_{p n} B_{m}; \end{screen} Symmetrisation (i.e.~using plus signs for all terms) is handled by the \subscommand{sym} algorithm. ~ \cdbseealgo{sym} \cdbseealgo{young_project} \cdbseealgo{young_project_tensor} cadabra-1.39/doc/algorithms/asymprop.tex000066400000000000000000000001101234107666300203350ustar00rootroot00000000000000\cdbalgorithm{asymprop}{} Remove all traces of anti-symmetric tensors. cadabra-1.39/doc/algorithms/breakgendelta.tex000066400000000000000000000007511234107666300212660ustar00rootroot00000000000000\cdbalgorithm{breakgendelta}{} Convert generalised delta symbols to products of normal Kronecker delta symbols with two indices. \begin{screen}{1,2} \delta{#}::KroneckerDelta. \delta_{m}^{n}_{p}^{q}; @breakgendelta!(%); 1/2 \delta_{m}^{n} \delta_{p}^{q} - 1/2 \delta_{p}^{n} \delta_{m}^{q}; \end{screen} (This is more efficient than projecting with the Young projector and then canonicalising). \cdbseealgo{reduce_gendelta} \cdbseeprop{KroneckerDelta} \cdbseealgo{young_project_tensor} cadabra-1.39/doc/algorithms/canonicalise.tex000066400000000000000000000034601234107666300211260ustar00rootroot00000000000000\cdbalgorithm{canonicalise}{} \label{loc_canonicalise} Canonicalise a product of tensors, using the mono-term\index{mono-term symmetries} index symmetries of the individual tensors and the exchange symmetries of identical tensors. Tensor exchange takes into account commutativity properties of identical tensors. Note that this algorithm does not take into account multi-term symmetries such as the Ricci identity of the Riemann tensor; those canonicalisation procedures require the use of \subscommand{young\_project\_tensor} or \subscommand{young\_project\_product}. Similarly, dimension-dependent identities are not taken into account, use \subscommand{decompose\_product} for those. In order to specify symmetries of tensors you need to use symmetry properties such as \subsprop{Symmetric}, \subsprop{AntiSymmetric} or \subsprop{TableauSymmetry}. The following example illustrates this. \begin{screen}{1,2,3,4} A_{m n}::AntiSymmetric. B_{p q}::Symmetric. A_{m n} B_{m n}; @canonicalise!(%); 0; \end{screen} If the various terms in an expression use different index names, you may need an additional call to \subscommand{rename\_dummies} before \subscommand{collect\_terms} is able to collect all terms together: \begin{screen}{1,2,3,4,5,7,9} {m,n,p,q,r,s}::Indices. A_{m n}::AntiSymmetric. C_{p q r}::AntiSymmetric. A_{m n} C_{m n q} + A_{s r} C_{s q r}; @canonicalise!(%); A_{m n} * C_{q m n} - A_{r s} * C_{q r s}; @rename_dummies!(%); A_{m n} * C_{q m n} - A_{m n} * C_{q m n}; @collect_terms!(%); 0; \end{screen} If you have symmetric or anti-symmetric tensors with many indices, it sometimes pays off to sort them to the end of the expression (this may speed up the canonicalisation process considerably). \cdbseealgo{young_project_tensor} \cdbseealgo{decompose_product} \cdbseealgo{rename_dummies} \cdbseealgo{collect_terms} cadabra-1.39/doc/algorithms/canonicalorder.tex000066400000000000000000000012241234107666300214550ustar00rootroot00000000000000\cdbalgorithm{canonicalorder}{} Orders the indicated objects in the expression in canonical order. On a simple product of objects it works as a partial product sort, \begin{screen}{1,2} C B E D A; @canonicalorder!(%)(A, B, E); C A B D E; \end{screen} It can, however, also be used to sort indices. Thereby, it facilitates imposing index symmetry on a tensor with open indices, as the following example illustrates. \begin{screen}{1,2} A^{m n p} B^{q r} + A^{q m} B^{n p r}; @canonicalorder!(%)( ^{m}, ^{n}, ^{p}, ^{r}, ^{q} ); A^{m n p} B^{r q} + A^{m n} B^{p r q}; \end{screen} ~ \cdbseealgo{acanonicalorder} \cdbseealgo{prodsort} \cdbseealgo{canonicalise} cadabra-1.39/doc/algorithms/coefficients.tex000066400000000000000000000003211234107666300211300ustar00rootroot00000000000000\cdbalgorithm{coefficients}{} Create a list of the coefficients of the powers of the indicated object. \begin{screen}{1,2,3} a + b x**2 + c x + d x**7; @coefficients(%){x}; \end{screen} \cdbseealgo{range} cadabra-1.39/doc/algorithms/collect_factors.tex000066400000000000000000000010771234107666300216460ustar00rootroot00000000000000\cdbalgorithm{collect\_factors}{} Collect factors in a product that differ only by their exponent. Note that factors containing sub- or superscripted indices do not get collected (i.e.~$A_m A^m$ does not get reduced to $(A_m)^2$). \begin{screen}{1,2} A A B A B A; @collect_factors!(%); A**4 B**2; \end{screen} Arbitrary powers can be collected this way, \begin{screen}{1,2} X X**(-1) X**(-4); @collect_factors!(%); X**(-3); \end{screen} The exponent notation can be expanded again using \subscommand{expand\_power}. ~ \cdbseealgo{expand_power} \cdbseealgo{collect_terms} cadabra-1.39/doc/algorithms/collect_terms.tex000066400000000000000000000010511234107666300213270ustar00rootroot00000000000000\cdbalgorithm{collect\_terms}{} \label{loc_collect_terms} Collect terms in a sum that differ only by their numerical pre-factor. This is called automatically on all new input, and also by some algorithms (in which case it will be indicated in the description of the command), but in general has to be called by hand. Note that this command only collects terms which are identical, it does not collect terms which are different but mathematically equivalent. See~\subscommand{sumsort} for an example. \cdbseealgo{collect_factors} \cdbseealgo{sumsort} cadabra-1.39/doc/algorithms/combine.tex000066400000000000000000000010461234107666300201100ustar00rootroot00000000000000\cdbalgorithm{combine}{} Combine two consecutive objects with indexbrackets and consecutive contracted indices into one object with an indexbracket. An example with two contracted matrices: \begin{screen}{1,2} (\Gamma_r)_{\alpha\beta} (\Gamma_{s t u})_{\beta\gamma}; @combine!(%); (\Gamma_r \Gamma_{s t u})_{\alpha\gamma}; \end{screen} An example with a matrix and a vector: \begin{screen}{1,2} (\Gamma_r)_{\alpha\beta} v_{\beta}; @combine!(%); (\Gamma_{r} v)_{\alpha}; \end{screen} The inverse is done by \subscommand{expand}. \cdbseealgo{expand} cadabra-1.39/doc/algorithms/decompose.tex000066400000000000000000000013051234107666300204500ustar00rootroot00000000000000\cdbalgorithm{decompose}{} Decompose a tensor monomial on a given basis of monomials. The basis should be given in the second argument. All tensor symmetries, including those implied by Young tableau Garnir symmetries, are taken into account. Example, \begin{screen}{0,1,2,3,5,6} {m,n,p,q}::Indices(vector). {m,n,p,q}::Integer(0..10). R_{m n p q}::RiemannTensor. R_{m n q p} R_{m p n q}; @decompose!(%)( R_{m n p q} R_{m n p q} ); { -1/2 }; \end{screen} Note that this algorithm does not yet take into account dimension-dependent identities, but it is nevertheless already required that the index range is specified. \cdbseealgo{young_project_tensor} \cdbseealgo{canonicalise} \cdbseeprop{TableauSymmetry} cadabra-1.39/doc/algorithms/decompose_product.tex000066400000000000000000000022331234107666300222110ustar00rootroot00000000000000\cdbalgorithm{decompose\_product}{} Decompose a product of tensors by writing it out in terms of irreducible Young tableau representations, discarding the ones which vanish in the indicated dimension, and putting the results back together again. This algorithm can thus be used to equate terms which are identical only in certain dimensions. If there are no dimension-dependent identities playing a role in the product, then \subscommand{decompose\_product} returns the original expression, \begin{screen}{1,2,3,4,5,6,7} { m, n, p, q }::Indices(vector). { A_{m n p}, B_{m n p} }::AntiSymmetric. A_{m n p} B_{m n q} - A_{m n q} B_{m n p}. { m, n, p, q }::Integer(1..4). @decompose_product!(%); @canonicalise!(%); @collect_terms!(%); A_{m n p} B_{m n q} - A_{m n q} B_{m n p}; \end{screen} However, in the present example, a Schouten identity makes the expression vanish identically in three dimensions, \begin{screen}{1,2,3,4} { m, n, p, q }::Integer(1..3). @decompose_product!(%); @canonicalise!(%): @collect_terms!(%); 0; \end{screen} Note that \subscommand{decompose\_product} is unfortunately computationally expensive, and is therefore not practical for large dimensions. cadabra-1.39/doc/algorithms/depprint.tex000066400000000000000000000006161234107666300203230ustar00rootroot00000000000000\cdbalgorithm{depprint}{} Display an expression together with all properties of the symbols that appear in this expression. This is a very useful command if you want to extract a result from a long calculation and write it in a separate file for further processing. \begin{screen}{1,2} \Gamma{#}::GammaMatrix. {m,n,p,q}::Indices. \Gamma_{m n p}; @depprint(%); \end{screen} ~ \cdbseealgo{print} cadabra-1.39/doc/algorithms/distribute.tex000066400000000000000000000016151234107666300206540ustar00rootroot00000000000000\cdbalgorithm{distribute}{} Rewrite a product of sums as a sum of products, as in \begin{equation} a\,(b+c) \rightarrow a\,b + a\,c\, . \end{equation} This would read \begin{screen}{1,2} a (b+c); @distribute!(%); a b + a c; \end{screen} The algorithm in fact works on all objects which carry the \subsprop{Distributable} property, \begin{screen}{1,2,3} Op{#}::Distributable. Op(A+B); @distribute!(%); Op(A) + Op(B); \end{screen} The primary example of a property which inherits the \subsprop{Distributable} property is \subsprop{PartialDerivative}. The \subscommand{distribute} algorithm thus also automatically writes out partial derivatives of sums as sums of partial derivatives, \begin{screen}{1,2,3} \partial{#}::PartialDerivative. \partial_{m}(A + B + C): @distribute!(%); \partial_{m}(A) + \partial_{m}(B) + \partial_{m}(C); \end{screen} ~ \cdbseeprop{Distributable} \cdbseeprop{PartialDerivative} cadabra-1.39/doc/algorithms/drop_weight.tex000066400000000000000000000024651234107666300210150ustar00rootroot00000000000000\cdbalgorithm{drop\_weight}{} Drop those terms for which a product has the indicated weight. Weights are computed by making use of the \subsprop{Weight} property of symbols. This algorithm does the opposite of \subscommand{keep\_weight}. As an example, consider the simple case in which we want to drop all terms with 3~fields. This is done using \begin{screen}{1,2,3} {A,B}::Weight(label=field). A B B + A A A + A B + B: @drop_weight!(%){field}{3}; A B + B; \end{screen} However, you can also do more complicated things by assigning non-unit weights to symbols, as in the example below, \begin{screen}{1,2,3,4} {A,B}::Weight(label=field). C::Weight(label=field, value=2). A B B + A A A + A B + A C + B: @drop_weight!(%){field}{3}; A B + B; \end{screen} Weights can be ``inherited'' by operators by using the \subsprop{WeightInherit} property. Here is an example using partial derivatives, \begin{screen}{1,2,3,4,6} {\phi,\chi}::Weight(label=small, value=1). \partial{#}::PartialDerivative. \partial{#}::WeightInherit(label=all, type=Multiplicative). \phi \partial_{0}{\phi} + \partial_{0}{\lambda} + \lambda \partial_{3}{\chi}: @drop_weight!(%){small}{1}; \phi \partial_{0}{\phi} + \partial_{0}{\lambda}; \end{screen} ~ \cdbseealgo{keep_weight} \cdbseeprop{Weight} \cdbseeprop{WeightInherit} cadabra-1.39/doc/algorithms/dualise_tensor.tex000066400000000000000000000026651234107666300215240ustar00rootroot00000000000000\cdbalgorithm{dualise\_tensor}{} Dualises tensors which have been declared \subsprop{SelfDual} according to the formula \begin{equation} F_{\mu_{n+1}\cdots \mu_{d}}\;\; \rightarrow\;\; *F_{\mu_{n+1}\cdots \mu_{d}} = \frac{1}{n!} \epsilon_{\mu_{n+1}\cdots\mu_d}{}^{\mu_1\cdots\mu_n} F_{\mu_1\cdots \mu_n}\, . \end{equation} In order for this to work the indices on the tensor have to be declared with \subsprop{Indices} and their range should have been specified with \subsprop{Integer}. \begin{screen}{1,2,3,4,5} {m,n,p,q,r#}::Indices. {m,n,p,q,r#}::Integer(0..5). F_{m n p}::SelfDual. A_{q} F_{m n p} F_{m n p}; @dualise_tensor!(%); 1/36 A_{q} \epsilon_{m n p r1 r2 r3} F_{r1 r2 r3} \epsilon_{m n p r4 r5 r6} F_{r4 r5 r6}; \end{screen} As indices are by default position-free, all indices on the epsilon tensors are generated as lower indices in the example above. Here is a modification which takes index positions into account: \begin{screen}{1,2,3,4,5} {m,n,p,q,r#}::Indices(position=fixed). {m,n,p,q,r#}::Integer(0..5). F_{m n p}::SelfDual. F^{m n p}::SelfDual. A_{q} F_{m n p} F^{m n p}; @dualise_tensor!(%); 1/36 A_{q} \epsilon_{m n p}^{r1 r2 r3} F_{r1 r2 r3} \epsilon^{m n p r4 r5 r6} F_{r4 r5 r6}; \end{screen} Products of epsilon tensors can be expanded in terms of Kronecker delta symbols with \subscommand{epsprod2gendelta}. \cdbseeprop{SelfDual} \cdbseeprop{Indices} \cdbseeprop{Integer} \cdbseealgo{epsprod2gendelta} cadabra-1.39/doc/algorithms/einsteinify.tex000066400000000000000000000012461234107666300210240ustar00rootroot00000000000000\cdbalgorithm{einsteinify}{} In an expression containing dummy indices at the same position (i.e.~either both subscripts or both superscripts), raise one of the indices. \begin{screen}{1,2} A_{m} A_{m}; @einsteinify!(%); A^{m} A_{m}; \end{screen} If an additional argument is given to this command, it instead inserts ``inverse metric'' objects, with the name as indicated by the additional argument. \begin{screen}{1,2} {m,n}::Indices. A_{m} A_{m}; @einsteinify!(%){\eta}; A_{m} A_{n} \eta^{m n}; \end{screen} Note that the second form requires that there are enough dummy indices defined through the use of \subsprop{Indices}. \cdbseealgo{eliminate_kr} \cdbseeprop{Indices} cadabra-1.39/doc/algorithms/eliminate_kr.tex000066400000000000000000000013111234107666300211320ustar00rootroot00000000000000\cdbalgorithm{eliminate\_kr}{} Eliminates Kronecker delta symbols by performing index contractions. Also replaces contracted Kronecker delta symbols with the range over which the index runs, if known. \begin{screen}{1,2,3} \delta_{m n}::KroneckerDelta. A_{m p} \delta_{p q} B_{q n}; @eliminate_kr!(%); A_{m q} B_{q n}; \end{screen} The index range is set as usual with \subsprop{Integer}, \begin{screen}{1,2,3,4} {m,n,p,q}::Integer(0..d-1). \delta_{m n}::KroneckerDelta. \delta_{p q} \delta_{p q}; @eliminate_kr!(%); d; \end{screen} In order to eliminate metric factors (i.e.~to `raise' and 'lower' indices) use the algorithm \subscommand{eliminate\_metric}. \cdbseeprop{Integer} \cdbseealgo{eliminate_metric} cadabra-1.39/doc/algorithms/eliminate_metric.tex000066400000000000000000000011261234107666300220050ustar00rootroot00000000000000\cdbalgorithm{eliminate\_metric}{} Eliminates metric and inverse metric objects. \begin{screen}{1,2,3,4,5,6,7,8,10} {m, n, p, q, r}::Indices(vector, position=fixed). {m, n, p, q, r}::Integer(0..9). g_{m n}::Metric. g^{m n}::InverseMetric. g_{m}^{n}::KroneckerDelta. g^{m}_{n}::KroneckerDelta. g_{m p} g^{p m}; @eliminate_metric!(%); g^{p}_{p}; @eliminate_kr!(%); 10; \end{screen} Other elimination commands of a similar type are \subscommand{eliminate\_kr} for Kronecker delta symbols and \subscommand{eliminate\_vielbein} for vielbeine. \cdbseealgo{eliminate_kr} \cdbseealgo{eliminate_vielbein} cadabra-1.39/doc/algorithms/eliminate_vielbein.tex000066400000000000000000000007701234107666300223230ustar00rootroot00000000000000\cdbalgorithm{eliminate\_vielbein}{} Eliminates vielbein objects. \begin{screen}{1,2,3,4,5} { m, n, p }::Indices(flat). { \mu, \nu, \rho }::Indices(curved). e_{m \mu}::Vielbein. H_{m n p} e_{m \mu}; @eliminate_vielbein!(%){H_{\mu\nu\rho}}; H_{\mu n p}; \end{screen} Other elimination commands of a similar type are \subscommand{eliminate\_kr} for Kronecker delta symbols and \subscommand{eliminate\_metric} for metric and inverse metric objects. \cdbseealgo{eliminate_kr} \cdbseealgo{eliminate_metric} cadabra-1.39/doc/algorithms/eliminateeps.tex000066400000000000000000000012471234107666300211560ustar00rootroot00000000000000\cdbalgorithm{eliminateeps}{} %{\bf CONTAINS KNOWN BUGS} Given an epsilon tensor and a self-dual tensor contracted with it, rewrite the self-dual tensor as epsilon times itself. \begin{screen}{1,2} F_{m n p}::SelfDual. \eps_{m n p q r s}::EpsilonTensor. \eps_{m n p q r s} F_{q r s}; @eliminateeps!(%){F_{m n p}}; \end{screen} At a further stage one can then use the command \subscommand{epsprod2gendelta} to remove the epsilons altogether the arguments contain a list of all tensors for which self-duality can be applied). Uses the the tensor with the largest number of indices in common with the epsilon symbol (can be more than one, in which case more terms are generated). cadabra-1.39/doc/algorithms/end.tex000066400000000000000000000003621234107666300172420ustar00rootroot00000000000000\cdbalgorithm{end}{} This is a marker which can be used in an input file to make the program stop reading (working just like ``{\tt $\backslash$end\{document\}}'' does for \LaTeX{} or ``{\tt $\backslash$end} for \TeX{}). \cdbseealgo{quit} cadabra-1.39/doc/algorithms/epsprod2gendelta.tex000066400000000000000000000045241234107666300217420ustar00rootroot00000000000000\cdbalgorithm{epsprod2gendelta}{} Replace a product of two epsilon tensors with a generalised delta according to the expression \begin{equation} \epsilon^{r_1\cdots r_{d}} \epsilon_{s_1\cdots s_{d}} = \frac{1}{\sqrt{|g|}}\varepsilon^{r_1 \cdots r_{d}} \sqrt{|g|}\varepsilon_{s_1\cdots s_{d}} = \sgn g\, d!\, \delta^{r_1 \cdots r_{d}}_{s_1\cdots s_{d}}\, , \end{equation} where~$\sgn g$ denotes the signature of the metric~$g$ used to raise/lower the indices (see \subsprop{EpsilonTensor} for conventions on the epsilon tensor). When the indices are not ocurring up/down as in this expression, and the index position is not free, metric objects will be generated instead. Here is an example: \begin{screen}{1,2,3,4,5,6} {a,b,c,d}::Indices. {a,b,c,d}::Integer(1..3). \delta{#}::KroneckerDelta. \epsilon_{a b c}::EpsilonTensor(delta=\delta). \epsilon_{a b c} \epsilon_{a b d}; @epsprod2gendelta!(%); 2 \delta_{c d}; \end{screen} In order for this algorithm to work, you need to make sure that the epsilon symbols in your expression are declared as \subsprop{EpsilonTensor} \emph{and} that these declarations involve a specification of the {\tt delta} and/or {\tt metric} symbols. As you can see from this example, contracted indices inside the generalised delta are automatically eliminated, as the command \subscommand{reduce\_gendelta} is called automatically; if you do not want this use the optional argument ``\mbox{noreduce}''. Note that the results typically depend on the signature of the space-time, which can be introduced through the optional \verb|metric| argument of the \verb|EpsilonTensor| property. Compare the two examples below: \begin{screen}{1,2,3,4,6,7,8,11,12,13} {a,b,c,d}::Indices. {a,b,c,d}::Integer(1..3). \delta{#}::KroneckerDelta. \epsilon_{a b c}::EpsilonTensor(delta=\delta, metric=g_{a b}). g_{a b}::Metric(signature=-1). \epsilon_{a b c} \epsilon_{a b c}; @epsprod2gendelta!(%); -6; g_{a b}::Metric(signature=+1). \epsilon_{a b c} \epsilon_{a b c}; @epsprod2gendelta!(%); 6; \end{screen} Note that you need to specify the full symbol for the metric, including the indices, whereas the Kronecker delta argument only requires the name without the indices (because a contraction can generate generalised Kronecker delta symbols with any number of indices). \cdbseeprop{EpsilonTensor} \cdbseeprop{Indices} \cdbseeprop{KroneckerDelta} \cdbseeprop{Integer} cadabra-1.39/doc/algorithms/eqs.tex000066400000000000000000000004021234107666300172570ustar00rootroot00000000000000\cdbalgorithm{eqs}{} Shows all expressions currently in memory. \begin{screen}{1,2,3,4} A + B: one:= D: E + F: @eqs; 1:= A + B; one:= D; 3:= E + F; \end{screen} The internal form of expressions can be obtained using \subscommand{tree}. \cdbseealgo{tree} cadabra-1.39/doc/algorithms/expand.tex000066400000000000000000000022631234107666300177550ustar00rootroot00000000000000\cdbalgorithm{expand}{} Write out products of matrices and vectors inside indexbrackets, inserting new dummy indices for the contraction. This requires that the objects inside the index bracket are properly declared to have \subsprop{Matrix} or \subsprop{ImplicitIndex} properties. Here is an example with multiple matrices: \begin{screen}{1,2,3} {a,b,c,d,e}::Indices. {A,B,C,D}::Matrix. (A B C D)_{a b}; @expand!(%); A_{a c} B_{c d} C_{d e} D_{e b}; \end{screen} Compare the above to the following example, in which one of the objects inside the bracket is no longer a matrix: \begin{screen}{1,2,3} {a,b,c,d,e}::Indices. {A,B,D}::Matrix. (A B C D)_{a b}; @expand!(%); A_{a c} B_{c d} C D_{d b}; \end{screen} Finally, an example with matrices carrying additional labels, as well as a vector object: \begin{screen}{1,2} {\alpha,\beta}::Indices. \Gamma{#}::Matrix. v::ImplicitIndex. (\Gamma_{r} v)_{\alpha}; @expand!(%); (\Gamma_{r})_{\alpha \beta} v_{\beta}; \end{screen} Note that in all cases, the indices on the indexbracket have to be part of a large enough set so that the dummy indices can be generated. \cdbseeprop{Matrix} \cdbseeprop{ImplicitIndex} \cdbseeprop{Indices} \cdbseealgo{combine} cadabra-1.39/doc/algorithms/expand_power.tex000066400000000000000000000011531234107666300211660ustar00rootroot00000000000000\cdbalgorithm{expand\_power}{} Expand powers into repeated products, i.e.~do the opposite of \subscommand{collect\_factors}. For example, \begin{screen}{1,2,4,5,7} (A B)**3: @expand_power!(%); (A * B) * (A * B) * (A * B); @prodflatten!(%): @prodsort!(%); A A A B B B; @collect_factors!(%); A**3 * B**3; \end{screen} This command automatically takes care of index relabelling when necessary, as in the following example, \begin{screen}{1,2,3,4} {m,n,p,q,r}::Indices(vector). (A_m B_m)**3: @expand_power!(%): @prodflatten!(%); A_{m} * B_{m} * A_{n} * B_{n} * A_{p} * B_{p}; \end{screen} ~ \cdbseealgo{collect_factors} cadabra-1.39/doc/algorithms/expand_product_shorthand.tex000066400000000000000000000011471234107666300235670ustar00rootroot00000000000000\cdbalgorithm{expand\_product\_shorthand}{} Reverse of the \subscommand{product\_shorthand} algorithm. In addition to the two tensor names, it takes a number denoting the total number of indices. \begin{screen}{1,2,3,5} F_{m n p q}::Symmetric. G_{m n p q}::Symmetric. @product_shorthand![ F_{a b c d} G_{a b d f} ]{F}{G}; F_{c} G_{f}; @expand_product_shorthand!(%){F}{G}{4}; F_{c a b d} G_{f a b d}; \end{screen} Note that writing a product as a shorthand and then expanding again may re-order the indices, as in the example above. \cdbseealgo{product_shorthand} \cdbseeprop{Symmetric} \cdbseeprop{AntiSymmetric} cadabra-1.39/doc/algorithms/factor_in.tex000066400000000000000000000012661234107666300204440ustar00rootroot00000000000000\cdbalgorithm{factor\_in}{} Given a list of symbols, this algorithm collects terms in a sum that only differ by pre-factors consisting of these given symbols. As an example, \begin{screen}{1,2} a b + a c + a d: @factor_in!(%){b,c}; (b + c) a + a d; \end{screen} The name is perhaps most easily understood by thinking of it as a complement to {\tt factor\_out}. Or in case you are familiar with FORM, {\tt factor\_in} is like its {\tt antibracket} statement. The algorithm of course also works with indexed objects, as in \begin{screen}{1,2} A_{m} B_{m} + C_{m} A_{m}; @factor_in!(%){B_{n},C_{n}}; (B_{m} + C_{m}) A_{m}; \end{screen} (this is still work in progress). \cdbseealgo{factor_out} cadabra-1.39/doc/algorithms/factor_out.tex000066400000000000000000000015041234107666300206400ustar00rootroot00000000000000\cdbalgorithm{factor\_out}{} Given a list of symbols, this algorithm tried to factor those symbols out of terms. As an example, \begin{screen}{1,2} a b + a c e + a d: @factor_out!(%){a}; a ( b + c e + d ); \end{screen} In case you are familiar with FORM, {\tt factor\_out} is like its {\tt bracket} statement. If you add more factors to factor out, it works as in \begin{screen}{1,2} a b + a c e + a c + c e + c d + a d: @factor_out!(%){a,c}; a (b + d) + c ( e + d ) + a c (e + 1); \end{screen} That is, separate terms will be generated for terms which differ by powers of the factors to be factored out. The algorithm of course also works with indexed objects, as in \begin{screen}{1,2} A_{m} B_{m} + C_{m} A_{m}; @factor_out!(%){A_{m}}; A_{m} (B_{m} + C_{m}) ; \end{screen} (this is still work in progress). \cdbseealgo{factor_in} cadabra-1.39/doc/algorithms/factorise.tex000066400000000000000000000010321234107666300204460ustar00rootroot00000000000000\cdbalgorithm{factorise}{} Given a list of symbols, this algorithm collects terms in a sum that only differ by pre-factors consisting of these given symbols. As an example, \begin{screen}{1,2} a b + a c + a d: @factorise!(%){b,c}; (b + c) a + a d; \end{screen} This is like the {\tt antibracket} statement of FORM. A better name is probably {\tt factor\_in}. The algorithm of course also works with indexed objects, as in \begin{screen}{1,2} A_{m} B_{m} + C_{m} A_{m}; @factorise!(%){B_{n},C_{n}}; (B_{m} + C_{m}) A_{m}; \end{screen} ~ cadabra-1.39/doc/algorithms/fierz.tex000066400000000000000000000014501234107666300176120ustar00rootroot00000000000000\cdbalgorithm{fierz}{} Perform a Fierz transformation on a product of four spinors. \begin{screen}{1,2} {\theta,\chi,\psi,\lambda}::Spinor(dimension=4, type=Majorana). {m,n,p#}::Indices. {m,n,p}::Integer(0..3). \Gamma{#}::GammaMatrix. \bar{#}::DiracBar. \bar{\theta} \Gamma_{m} \chi \bar{\psi} \Gamma^{m} \lambda; @fierz!(%)(\theta, \lambda, \psi, \chi); \end{screen} The argument to \subscommand{fierz} is the required order of the fermions; note that this algorithm does not flip around Majorana spinors and \subscommand{spinorsort} should be used for that. Also note that it is important to define not only the symbols representing the spinors, Dirac bar and gamma matrices, but also the range of the indices. \cdbseealgo{spinorsort} \cdbseeprop{GammaMatrix} \cdbseeprop{DiracBar} \cdbseeprop{Spinor} cadabra-1.39/doc/algorithms/gammasplit.tex000066400000000000000000000015421234107666300206330ustar00rootroot00000000000000\cdbalgorithm{gammasplit}{} The opposite of \subscommand{join}: splits off a gamma matrix from a totally anti-symmetrised product, e.g. \begin{equation} \Gamma^{mnp} = \Gamma^{mn}\Gamma^p - 2\,\Gamma^{[m} \eta^{n]}{}_p\, . \end{equation} In code this reads \begin{screen}{1,2} \Gamma{#}::GammaMatrix(metric=\eta). \Gamma^{m n p}; @gammasplit(%); \Gamma^{m n} \Gamma^{p} - \Gamma^{m} \eta^{n p} + \Gamma^{n} \eta^{m p}; \end{screen} By default it splits of the one from the back, like in the example above, but with argument {\tt front} it will split from the front: \begin{screen}{1,2} \Gamma{#}::GammaMatrix(metric=\eta). \Gamma^{m n p}; @gammasplit(%){front}; \Gamma^{m} \Gamma^{n p} - \Gamma^{p} \eta^{m n} + \Gamma^{n} \eta^{m p}; \end{screen} ~ \cdbseealgo{join} \cdbseeprop{GammaMatrix} cadabra-1.39/doc/algorithms/impose_asym.tex000066400000000000000000000003101234107666300210120ustar00rootroot00000000000000\cdbalgorithm{impose\_asym}{} Impose anti-symmetry in external indices, that is, remove terms in the expression which have anti-symmetry imposed on more than one index sitting on a symmetric object. cadabra-1.39/doc/algorithms/impose_bianchi.tex000066400000000000000000000020331234107666300214420ustar00rootroot00000000000000\cdbalgorithm{impose\_bianchi}{} Removes terms which are proportional to the (Garnir generalised) Bianchi identity. It removes all products for which a set of indices in Garnir hook form is contracted with an anti-symmetric set. Here is a simple example with a Riemann tensor, \begin{screen}{1,2,3,4} A^{m n p}::AntiSymmetric. R_{m n p q}::RiemannTensor. R_{m n p q} A^{m n p}; @impose_bianchi!(%); 0; \end{screen} Here is a more complicated one using a \subsprop{TableauSymmetry} property, \begin{screen}{1,2,3,4} \epsilon^{m n p q}::EpsilonTensor. B_{m n p}::TableauSymmetry(shape={2,1}, indices={0,1,2}). \epsilon^{m n p q} B_{m n p}; @impose_bianchi!(%); 0; \end{screen} An alternative way to obtain the same result is to project each tensor using the generic \subscommand{young\_project\_tensor} algorithm, and then use \subscommand{distribute} followed by \subscommand{canonicalise}, but that generically takes much more time. \cdbseeprop{RiemannTensor} \cdbseeprop{TableauSymmetry} \cdbseealgo{young_project_tensor} \cdbseealgo{canonicalise} cadabra-1.39/doc/algorithms/index_rename.tex000066400000000000000000000012401234107666300211260ustar00rootroot00000000000000\cdbalgorithm{index\_rename}{} Replace index names. This should preferably be avoided, but can incidentally come in useful to relabel a large set of numbered indices in one go, as the following example shows. \begin{screen}{1,2} {m#,n#}::Indices(spacetime). A_{m1 m2 m3} B_{m4 m2}; @index_rename!(%){m}{n}{true}; A_{n1 m2 n3} B_{n4 m2}; \end{screen} The {\tt true} argument to the algorithm indicates that numbered indices starting with the given index name should be relabelled too. Generically, it is a better practise to avoid renaming indices altogether, and try to set up calculations such that they do not depend on the names of indices. \cdbseealgo{substitute} cadabra-1.39/doc/algorithms/indexlist.tex000066400000000000000000000001671234107666300205020ustar00rootroot00000000000000\cdbalgorithm{indexlist}{} Displays a list of all indices in an expression, together with their type (dummy or free). cadabra-1.39/doc/algorithms/indexsort.tex000066400000000000000000000012771234107666300205210ustar00rootroot00000000000000\cdbalgorithm{indexsort}{} Lexographically sorts indices of all tensors according to their Young tableau symmetries. This works in simple symmetric or anti-symmetric cases as expected: \begin{screen}{1,2} A_{m n}::AntiSymmetric. A_{n m}; @indexsort!(%); (-1) A_{m n}; \end{screen} It also sorts index groups in tensors with row exchange symmetries, such as the Riemann tensor, \begin{screen}{1,2} R_{a b c d}::RiemannTensor. R_{d c a b}; @indexsort!(%); (-1) R_{a b c d}; \end{screen} For more complicated canonicalisation algorithms, see \subscommand{canonicalise} as well as \subscommand{reduce}. \cdbseealgo{canonicalise} \cdbseealgo{reduce} \cdbseeprop{AntiSymmetric} \cdbseeprop{TableauSymmetry} cadabra-1.39/doc/algorithms/inner.tex000066400000000000000000000006651234107666300176150ustar00rootroot00000000000000\cdbalgorithm{inner}{} Construct an inner product between two lists appearing in a list, \begin{screen}{1,2,4} lst1:= {a_m, b_m ,c_m ,d_m ,e_m }: lst2:= @range[{1, @length[@(lst1)]}]; \{ 1,2,3,4,5 \}; @inner[ { @(lst1), @(lst2) } ]; a_m + 2 b_m + 3 c_m + 4 d_m + 5 e_m; \end{screen} In order to generate a list of the sum of elements, use \subscommand{list\_sum} instead. \cdbseealgo{list_sum} \cdbseealgo{length} \cdbseealgo{range} cadabra-1.39/doc/algorithms/join.tex000066400000000000000000000044671234107666300174450ustar00rootroot00000000000000\cdbalgorithm{join}{} Join two fully anti-symmetrised gamma matrix products according to the expression \begin{equation} \Gamma^{b_{1}\dots b_{n}}\Gamma_{a_{1}\dots a_{m}} = \sum_{p=0}^{\text{min}(n,m)}\ \frac{n! m!}{(n-p)! (m-p)! p!} \Gamma^{[b_{1}\ldots b_{n-p}}{}_{[a_{p+1}\ldots a_{m}} \eta^{b_{n-p+1}\ldots b_{n}]}{}_{a_{1}\ldots a_{m-p}]} \, . \end{equation} This is the opposite of \subscommand{gammasplit}. Without further arguments, the anti-symmetrisations will be left implicit. The argument ``{\tt expand}'' instead performs the sum over all anti-symmetrisations, which may lead to an enormous number of terms if the number of indices on the gamma matrices is large. Compare \begin{screen}{1,2} \Gamma{#}::GammaMatrix(metric=g). \Gamma_{m n} \Gamma_{p}; @join!(%); \Gamma_{m n p} + 2 \Gamma_{m} g_{n p}; \end{screen} with \begin{screen}{1,2} \Gamma{#}::GammaMatrix(metric=g). \Gamma_{m n} \Gamma_{p}; @join!(%){expand}; \Gamma_{m n p} + \Gamma_{m} g_{n p} - \Gamma_{n} g_{m p}; \end{screen} Note that the gamma matrices need to have a metric associated to them in order for this algorithm to work. In order to reduce the number somewhat, one can instruct the algorithm to make use of generalised Kronecker delta symbols in the result; these symbols are defined as \begin{equation} \delta^{r_1}{}_{s_1}{}^{r_2}{}_{s_2}\cdots{}^{r_n}{}_{s_n} = \delta^{[r_1}{}_{s_1}\delta^{r_2}{}_{s_2}\cdots {}^{r_n]}{}_{s_n}\, . \end{equation} Anti-symmetrisation is implied in the set of even-numbered indices. The use of these symbols is triggered by the ``{\tt gendelta}'' option, \begin{screen}{1,2} {m,n,p,q}::Indices(position=fixed). \Gamma{#}::GammaMatrix(metric=\delta). \Gamma_{m n} \Gamma^{p q}; @join!(%){expand}{gendelta}; \Gamma_{m n}^{p q} + \Gamma_{m}^{q} \delta_{n}^{p} - \Gamma_{m}^{p} \delta_{n}^{q} - \Gamma_{n}^{q} \delta_{m}^{p} + \Gamma_{n}^{p} \delta_{m}^{q} + 2 \delta_{n}^{p}_{m}^{q}; \end{screen} Finally, to select only a single term (for a given $p$) in this expansion, give the join an argument with the value of $p$. \begin{screen}{1,2} \Gamma{#}::GammaMatrix(metric=g). \Gamma_{m n} \Gamma_{p}; @join!(%){expand}{3}; \Gamma_{m n p}; \end{screen} This option can also be combined with {\tt gendelta} if required. \cdbseeprop{GammaMatrix} \cdbseeprop{KroneckerDelta} \cdbseealgo{gammasplit} cadabra-1.39/doc/algorithms/keep_terms.tex000066400000000000000000000004221234107666300206270ustar00rootroot00000000000000\cdbalgorithm{keep\_terms}{} Keep the~$m$th to the~$n$th terms in a sum, dropping all others. \begin{screen}{1,2,3} A + B + C + D + E + F; @keep_terms!(%){3}{5}; D + E + F; \end{screen} Note that counting starts from zero. \cdbseealgo{keep_weight} \cdbseealgo{take_match} cadabra-1.39/doc/algorithms/keep_weight.tex000066400000000000000000000045021234107666300207670ustar00rootroot00000000000000\cdbalgorithm{keep\_weight}{} Keep only those terms for which a product has the indicated weight. Weights are computed by making use of the \subsprop{Weight} property of symbols. This algorithm does the opposite of \subscommand{drop\_weight}. As an example, consider the simple case in which we want to keep all terms with 3~fields. This is done using \begin{screen}{1,2,3} {A,B}::Weight(label=field). A B B + A A A + A B + B: @keep_weight!(%){field}{3}; A B B + A A A \end{screen} However, you can also do more complicated things by assigning non-unit weights to symbols, as in the example below, \begin{screen}{1,2,3,4} {A,B}::Weight(label=field). C::Weight(label=field, value=2). A B B + A A A + A B + A C + B: @keep_weight!(%){field}{3}; A B B + A A A + A C \end{screen} Weights also apply to tensorial expressions. Consider e.g.~a situation in which we have a polynomial of the type \begin{equation} c^{a} + c^{a}_{b} x^{b} + c^{a}_{b c} x^{b} x^{c} + c^{a}_{b c d} x^{b} x^{c} x^{d}; \end{equation} and we want to keep only the quadratic term. This can be done using \begin{screen}{1,2,3,4} x^{a}::Weight(label=crd, value=1). c^{#}::Weight(label=crd, value=0). c^{a} + c^{a}_{b} x^{b} + c^{a}_{b c} x^{b} x^{c} + c^{a}_{b c d} x^{b} x^{c} x^{d}; @keep_weight!(%){crd}{2}; c^{a}_{b c} x^{b} x^{c}; \end{screen} Weights can be ``inherited'' by operators by using the \subsprop{WeightInherit} property. Here is an example using partial derivatives, \begin{screen}{1,2,3,4,6} {\phi,\chi}::Weight(label=small, value=1). \partial{#}::PartialDerivative. \partial{#}::WeightInherit(label=all, type=Multiplicative). \phi \partial_{0}{\phi} + \partial_{0}{\lambda} + \lambda \partial_{3}{\chi}: @keep_weight!(%){small}{1}; \lambda \partial_{3}{\chi}; \end{screen} If you want to use weights for dimension counting, in which operators can also carry a dimension themselves (e.g.~derivatives), then use the \verb|self| attribute, \begin{screen}{1,2,3,4,6} {\phi,\chi}::Weight(label=length, value=1). x::Coordinate. \partial{#}::PartialDerivative. \partial{#}::WeightInherit(label=length, type=Multiplicative, self=-1). \phi \partial_{x}{\phi} + \phi\chi + \partial_{x}{ \phi \chi**2 }; @keep_weight!(%){length}{1}; \end{screen} This keeps only the first term. ~ \cdbseealgo{drop_weight} \cdbseeprop{Weight} \cdbseeprop{WeightInherit} cadabra-1.39/doc/algorithms/length.tex000066400000000000000000000017501234107666300177570ustar00rootroot00000000000000\cdbalgorithm{length}{} Replaces the expression with its length, that is, the number of terms in a sum, the number of factors in a product or the number of elements in a list. \begin{screen}{1,2,4,5,7,8} lst:= {a,b,c,d}: @length(%); lst:= 4; sum:= a + b + c + d + e: @length(%); sum:= 5; prod:= a*b*c: @length(%); prod:= 3; \end{screen} Note that the original expression gets replaced; if you need a new expression use a square-bracket construction as in \begin{screen}{1,2} sum:= a + b + c + d; @length[@(sum)]; 2:= 4; \end{screen} Here is a more complicated example which takes all terms except the first and last from an expression: \begin{screen}{1,2} a+b+c+d+e+f+g; @take(%){ 1..@collect_terms[@length[@(%)]-2] }; b+c+d+e+f; \end{screen} (remember that counting terms starts from zero). If you just want to display the number of elements, use \subscommand{number\_of\_terms}; this is an output command and does not change the expression. \cdbseealgo{number_of_terms} \cdbseealgo{take_match} cadabra-1.39/doc/algorithms/list_sum.tex000066400000000000000000000007221234107666300203330ustar00rootroot00000000000000\cdbalgorithm{list\_sum}{} In an expression containing sums of identical-length lists, create one new list constructed by adding the elements at the same position in each list. Example, \begin{screen}{1,2,3} {a, b, 7 c + q, d, e} - {-f, g, h, i, j}: @list_sum!(%): @sumflatten!(%); \{ a + f, b - g, 7c + q - h, d - i, e - j \}; \end{screen} To generate a list of the products of the elements, use \subscommand{inner} instead. \cdbseealgo{inner} \cdbseealgo{range} cadabra-1.39/doc/algorithms/listflatten.tex000066400000000000000000000005251234107666300210260ustar00rootroot00000000000000\cdbalgorithm{listflatten}{} Turns nested lists into one list, as in \begin{equation} \{ a, b, \{ c, d \} \} \rightarrow \{ a, b, c, d \}\,. \end{equation} In terms of code this reads \begin{screen}{1,2} {a,b,{c,d}}; @listflatten!(%); \{ a,b,c,d \}; \end{screen} ~ \cdbseealgo{prodflatten} \cdbseealgo{listflatten} \cdbseealgo{distribute} cadabra-1.39/doc/algorithms/lr_tensor.tex000066400000000000000000000027341234107666300205100ustar00rootroot00000000000000\cdbalgorithm{lr\_tensor}{} Compute the tensor product of two tableaux or filled tableaux. The algorithm acts on objects which have the \subsprop{Tableau} or \subsprop{FilledTableau} property, through which it is possible to set the dimension. The standard Littlewoord-Richardson algorithm is used to construct the tableaux in the tensor product. An example with \subsprop{Tableau} objects is given below. \begin{screen}{1,2,3} \tableau{#}::Tableau(dimension=10). \tableau{2}{2} \tableau{2}{2}; @lr_tensor!(%); \tableau{4 4} + \tableau{4 3 1} + \tableau{4 2 2} + \tableau{3 3 1 1} + \tableau{3 2 2 1} + \tableau{2 2 2 2}; \end{screen} In the graphical interface the output will show up as proper Young tableaux, \begin{equation} \tableau{4 4} + \tableau{4 3 1} + \tableau{4 2 2} + \tableau{3 3 1 1} + \tableau{3 2 2 1} + \tableau{2 2 2 2}; \end{equation} The same example, but now with \subsprop{FilledTableau} objects, is \begin{screen}{1,2,3} \tableau{#}::FilledTableau(dimension=10). \tableau{0,0}{1,1} \tableau{a,a}{b,b}: @lr_tensor!(%); \end{screen} This will again output a sum of \verb|\tableau| objects. In the graphical interface they will be typeset as \begin{equation} \ftableau{{0}{0}{a}{a},{1}{1}{b}{b}} + \ftableau{{0}{0}{a}{a},{1}{1}{b},{b}} + \ftableau{{0}{0}{a}{a},{1}{1},{b}{b}} + \ftableau{{0}{0}{a},{1}{1}{b},{a},{b}} + \ftableau{{0}{0}{a},{1}{1},{a}{b},{b}} + \ftableau{{0}{0},{1}{1},{a}{a},{b}{b}}; \end{equation} \cdbseeprop{Tableau} \cdbseeprop{FilledTableau} cadabra-1.39/doc/algorithms/lsolve.tex000066400000000000000000000006421234107666300200010ustar00rootroot00000000000000\cdbalgorithm{lsolve}{} Solve a system of linear equations over integers. Example, \begin{screen}{1,2} { a0+2*a2 + a3= 3, -a0 - a2 + a3= - (8/3) , a3 = 3}; @lsolve(%){a0,a2,a3}; {a0 = 34/3, a2 = (-17/3), a3 = 3}; \end{screen} Underdetermined and inconsistent systems are handled as expected: either some coefficients are left unfixed or the system is returned and an error message is printed. \cdbseealgo{decompose} cadabra-1.39/doc/algorithms/maple.tex000066400000000000000000000011751234107666300175750ustar00rootroot00000000000000\cdbalgorithm{maple}{} Feed an expression through the Maple computer algebra system. This allows you to e.g.~do trigonometric simplification or other `scalar computer algebra' for which \cdb does not have any built-in support. \begin{screen}{1,2,4,5} simplify( sin(x)**2 + cos(x)**2 ): @maple(%); 1; integrate( \sin(x)**2, x ): @maple(%); - 1/2 \sin(x) \cos(x) + 1/2 x; \end{screen} Note that reserved names, like the \verb|\sin| above, get converted to Maple notation automatically (and they get translated again when the result is read back into \cdb). This command is preliminary and not yet fully functional. \cdbseealgo{maxima} cadabra-1.39/doc/algorithms/maxima.tex000066400000000000000000000012011234107666300177410ustar00rootroot00000000000000\cdbalgorithm{maxima}{} Feed an expression through the Maxima computer algebra system. This allows you to e.g.~do trigonometric simplification or other `scalar computer algebra' for which \cdb does not have any built-in support. \begin{screen}{1,2,4,5} trigsimp( sin(x)**2 + cos(x)**2 ): @maxima(%); 1; integrate( \sin(x)**2, x ): @maxima(%); (1/2 * x - 1/4 * \sin(2 * x)); \end{screen} Note that reserved names, like the \verb|\sin| above, get converted to Maxima notation automatically (and they get translated again when the result is read back into \cdb). This command is preliminary and not yet fully functional. \cdbseealgo{maple} cadabra-1.39/doc/algorithms/mem.tex000066400000000000000000000006741234107666300172600ustar00rootroot00000000000000\cdbalgorithm{mem}{} Displays an overview of the current memory usage, of the form \begin{screen}{1,2} # of names : 32 # of rationals : 3 # of nodes : 22 (= 704 bytes) # of expressions: 2 \end{screen} Memory consumption can be limited by disabling expression histories with the \subsprop{KeepHistory} property, or by using \subscommand{amnesia}. \cdbseeprop{KeepHistory} \cdbseealgo{amnesia} \cdbseealgo{tree} \cdbseealgo{timing} cadabra-1.39/doc/algorithms/number_of_terms.tex000066400000000000000000000004661234107666300216670ustar00rootroot00000000000000\cdbalgorithm{number\_of\_terms}{} Displays the number of terms in a sum. \begin{screen}{1,2} A + B + C + D; @number_of_terms(%); 4; \end{screen} Note that this leaves the expression unmodified; if you want to use the number instead of just seeing it displayed, use \subscommand{length}. \cdbseealgo{length} cadabra-1.39/doc/algorithms/numerical_flatten.tex000066400000000000000000000012401234107666300221640ustar00rootroot00000000000000\cdbalgorithm{numerical\_flatten}{} Move numerical factors out of operators whenever possible. This is mostly useful in combination with derivative operators, as in the example below. \begin{screen}{1,2,3} \partial{#}::PartialDerivative. 3 A \partial{4 B}; @numerical_flatten!(%); 12 A \partial{B}; \end{screen} In contrast, the \subscommand{unwrap} algorithm moves non-numerical factors out of derivative operators. Objects to which this algorithm applies should carry the \subsprop{NumericalFlat} property (which the \subsprop{Derivative} objects inherit automatically). \cdbseeprop{NumericalFlat} \cdbseealgo{listflatten} \cdbseealgo{sumflatten} \cdbseealgo{unwrap} cadabra-1.39/doc/algorithms/output_format.tex000066400000000000000000000011541234107666300214040ustar00rootroot00000000000000\cdbalgorithm{output\_format}{} Set the output format according to the argument given. It can take one of the three values This can take one of the values {\tt cadabra}, {\tt mathematica}, {\tt reduce}, {\tt maple}, {\tt texmacs}, {\tt xcadabra}, {\tt mathml}. \begin{screen}{1} @output_format{mathematica}; A_{m n} B_{p q}; Tensor[A, {m, n}] * Tensor[B, {p, q}]; @output_format{reduce}; A(m,n) * B(p,q); \end{screen} Not all of these output formats are fully functional and some are meant only as an internal format (e.g.~{\tt xcadabra} is used for communication with the graphical front-end). \cdbseealgo{print} cadabra-1.39/doc/algorithms/permute.tex000066400000000000000000000041001234107666300201470ustar00rootroot00000000000000\cdbalgorithm{permute}{} Generic algorithm to generate permutations and combinations of elements in a list. It takes several arguments depending on the type of permutations which one wishes to generate. The simplest permutations are generated by stating whether items can be taken from the original set more than once (multiple-pick or single-pick), and stating the length of the permutation sets to be generated. An example with single-pick is \begin{screen}{1,2} {a,b,c,d}; @permute!(%){false}{3}; {{a, b, c}, {a, b, d}, {a, c, d}, {b, c, d}}; \end{screen} while an example with multiple-pick is \begin{screen}{1,2} {a,b,c,d}; @permute!(%){true}{2}; {{a, a}, {a, b}, {a, c}, {a, d}, {b, b}, {b, c}, {b, d}, {c, c}, {c, d}, {d, d}}; \end{screen} The length parameter is in fact fixing the length of the subsets in the result for which the order of the elements does not matter. Therefore, \begin{screen}{1,2} {a,b,c}; @permute!(%){false}{1,1}; {{a, b}, {a, c}, {b, a}, {b, c}, {c, a}, {c, b}}; \end{screen} Finally, it is also possible to generate all permutations with a given maximal length, \begin{screen}{1,2} {a,b,c}; @permute!(%){false}{<3}; {{a}, {b}, {c}, {a, b}, {a, c}, {b, c}}; \end{screen} More complicated permutations can be generated by assigning weights to the objects in the original list. Here is an example in which~$a,b,c$ have weights~$2,1,0$ respectively, and lists of length~3 are generated for which the total weight is~4. \begin{screen}{1,2} {a,b,c}; @permute!(%){true}{3}{2,1,0}{4}; {{a, a, c}, {a, b, b}}; \end{screen} Objects can be assigned more than one type of weight by simply repeating the two arguments associated to weights. For instance, if we in addition introduce another weight type, under which~$a,b,c$ have weight~$0,1,0$ respectively, and also impose that this weight should add up to~$2$, we get \begin{screen}{1,2} {a,b,c}; @permute!(%){true}{3}{2,1,0}{4}{0,1,0}{2}; {{a, b, b}}; \end{screen} This functionality is useful when constructing field polynomials restricted to certain length dimension or Grassmann number. \cdbseealgo{range} cadabra-1.39/doc/algorithms/pintegrate.tex000066400000000000000000000013661234107666300206430ustar00rootroot00000000000000\cdbalgorithm{pintegrate}{} Perform a partial integration. This requires an expression with an object carrying a \subsprop{PartialDerivative} property. The command should have the name of the partial derivative as an argument: \begin{screen}{1,2} \partial{#}::PartialDerivative. \partial_{m}{A} B C D; @pintegrate!(%){\partial}; (-1) \partial_{m}(B C D) A; @prodrule!(%): @distribute!(%); - \partial_{m}{B} C D A - B \partial_{m}{C} D A - B C \partial_{m}{D} A; \end{screen} See the tutorials and the manual for \subscommand{take\_match} and \subscommand{replace\_match} for examples in which only particular terms in an expression are selected and partially integrated. \cdbseealgo{take_match} \cdbseealgo{replace_match} \cdbseeprop{PartialDerivative} cadabra-1.39/doc/algorithms/pop.tex000066400000000000000000000004761234107666300173000ustar00rootroot00000000000000\cdbalgorithm{pop}{} Remove the last step of the indicated expression history. \begin{screen}{1,2,4} A (B + C); @distribute!(%); A B + A C; @pop(%); A (B + C); \end{screen} This only works if history keeping was not turned off with the \subsprop{KeepHistory} property. \cdbseealgo{amnesia} \cdbseeprop{KeepHistory} cadabra-1.39/doc/algorithms/print.tex000066400000000000000000000012241234107666300176260ustar00rootroot00000000000000\cdbalgorithm{print}{} Construct output from strings and \cdb expressions. Here is an example: \begin{screen}{1,2} \Gamma{#}::GammaMatrix(metric=\delta). @print["The result is : " ~ @join[\Gamma^{a b}\Gamma_{c}] ~ ";"]; The result is : (\Gamma^{a b}_{c} + 2 * \Gamma^{a} * \delta^{b}_{c}); \end{screen} As you can see in this example, expressions are joined together into one printable string by using the tilde character. Note that \subscommand{print} completely overrides the normal output of expressions: there is no expression number for instance. Also note that all active nodes are (as usual) completely expanded before the print algorithm is called. cadabra-1.39/doc/algorithms/print_status.tex000066400000000000000000000006431234107666300212350ustar00rootroot00000000000000\cdbalgorithm{print\_status}{} Toggles printing of status information. Status output is always enclosed inside easily distinguished \verb|| and \verb|| marks. \begin{screen}{1} @print_status{true}; A_{m n}; last_used_equation_number=1 1 A_{m n}; \end{screen} This is mostly used for communication with the graphical front-end. \cdbseealgo{output_format} cadabra-1.39/doc/algorithms/prodcollectnum.tex000066400000000000000000000003341234107666300215250ustar00rootroot00000000000000\cdbalgorithm{prodcollectnum}{} Collect factors in a product. This algorithm is called automatically so you usually do not need it. A related command is \subscommand{numerical\_flatten}. \cdbseealgo{numerical_flatten} cadabra-1.39/doc/algorithms/prodflatten.tex000066400000000000000000000007421234107666300210200ustar00rootroot00000000000000\cdbalgorithm{prodflatten}{} Removes brackets in a product, that is, makes changes of the type \begin{equation} a*(b*c) \rightarrow a*b*c\, . \end{equation} In terms of code this reads \begin{screen}{1,2} a (b c); @prodflatten!(%); a b c; \end{screen} The above is sometimes required because it is possible to write and keep nested products with brackets in order to improve readability of expressions. ~ \cdbseealgo{sumflatten} \cdbseealgo{listflatten} \cdbseealgo{distribute} cadabra-1.39/doc/algorithms/prodrule.tex000066400000000000000000000015711234107666300203330ustar00rootroot00000000000000\cdbalgorithm{prodrule}{} Apply the product rule or ``Leibnitz identity'' to an object which has the \subsprop{Derivative} property, i.e. \begin{equation} D(f\, g) = D(f)\, g + f\, D(g)\, . \end{equation} In terms of actual code this example would read \begin{screen}{1,2,3} D{#}::Derivative. D(f g); @prodrule!(%); D(f) g + f D(g); \end{screen} This of course also works for derivatives which explicitly mention indices or components, as well as for multiple derivatives, as in the example below. \begin{screen}{1,2,3,4,5} D{#}::Derivative. D_{m n}(f g); @prodrule!(%); @distribute!(%); @prodrule!(%); D_{n}{D_{m}(f)} g + D_{m}(f) D_{n}{g} + D_{n}{f} D_{m}(g) + f D_{n}{D_{m}(g)}; \end{screen} ~ % We may even do the one for generic n-th order derivatives, see % % http://mathworld.wolfram.com/LeibnizIdentity.html % \cdbseeprop{Derivative} \cdbseealgo{distribute} cadabra-1.39/doc/algorithms/prodsort.tex000066400000000000000000000025201234107666300203460ustar00rootroot00000000000000\cdbalgorithm{prodsort}{} Sort factors in a product, taking into account any \subsprop{SortOrder} properties. Also takes into account commutativity properties, such as \subsprop{SelfCommuting}. If no sort order is given, it first does a lexographical sort based on the name of the factor, and if two names are identical, does a sort based on the number of children and (if this number is equal) a lexographical comparison of the names of the children. The simplest sort is illustrated below, \begin{screen}{1,2} C B A D; @prodsort!(%); A B C D; \end{screen} We can declare the objects to be anti-commuting, which then leads to \begin{screen}{1,2,3} {A, B, C, D}::AntiCommuting. C B A D; @prodsort!(%); (-1) A B C D; \end{screen} For indexed objects, the anti-commutativity of components is indicated using the \subsprop{SelfAntiCommuting} property, \begin{screen}{1,2,3} \psi_{m}::SelfAntiCommuting. \psi_{n} \psi_{m} \psi_{p}; @prodsort!(%); (-1) \psi_{m} \psi_{n} \psi_{p}; \end{screen} Finally, the lexographical sort order can be overridden by using the \subsprop{SortOrder} property, \begin{screen}{1,2} {D, C, B, A}::SortOrder. {A, B, C, D}::AntiCommuting. C B A D; @prodsort!(%); (-1) D C B A; \end{screen} %\kcomment{KP}{Warning! Does not yet know about {$\backslash$pow}} \cdbseeprop{SortOrder} \cdbseeprop{Commuting} \cdbseeprop{AntiCommuting} cadabra-1.39/doc/algorithms/product_shorthand.tex000066400000000000000000000011441234107666300222250ustar00rootroot00000000000000\cdbalgorithm{product\_shorthand}{} Rewrites the product of two fully symmetric or anti-symmetric tensors in a compact form by removing the contracting dummy indices. \begin{screen}{1,2,3} F_{m n p q}::Symmetric. G_{m n p q}::Symmetric. @product_shorthand![ F_{a b c d} G_{a b d f} ]{F}{G}; F_{c} G_{f}; \end{screen} The two arguments denote the tensors to which the algorithm should apply. Expanding the product again in terms of the full tensors can be done with the algorithm \subscommand{expand\_product\_shorthand}. \cdbseealgo{expand_product_shorthand} \cdbseeprop{Symmetric} \cdbseeprop{AntiSymmetric} cadabra-1.39/doc/algorithms/projweyl.tex000066400000000000000000000017551234107666300203560ustar00rootroot00000000000000\cdbalgorithm{projweyl}{} Projects an expression onto Weyl spinors of positive chirality (this algorithm only works in even dimensions). On such a subspace, we have \begin{equation} \label{e:g10toeps} \Gamma^{r_1 \cdots r_{d}}\Big|_{\text{Weyl}} = \frac{1}{\sqrt{-g}}\epsilon^{r_1\cdots r_{d}} \, ,\quad \epsilon^{0\cdots (d-1)} = +1\, , \end{equation} and therefore all gamma matrices with more than $d/2$ indices can be converted to their ``dual'' gamma matrices. By repeated contraction of~\eqref{e:g10toeps} with gamma matrices on the left one deduces that \begin{equation} \Gamma^{r_1\cdots r_n}\Big|_{\text{Weyl}} = \frac{1}{\sqrt{-g}} \frac{(-1)^{\frac{1}{2}n(n+1)+1}}{(d-n)!} \Gamma_{s_1\cdots s_{d-n}}\Big|_{\text{Weyl}} \epsilon^{s_1\cdots s_{d-n} r_1\cdots r_n}\, . \end{equation} Here is an example: \begin{screen}{1,2} {m,n,p,q,r,s,t}::Indices. {m,n,p,q,r,s,t}::Integer(0..5). \Gamma{#}::GammaMatrix. \Gamma_{m n p q}; @projweyl!(%); \end{screen} \cdbseeprop{GammaMatrix} \cdbseealgo{join} cadabra-1.39/doc/algorithms/properties.tex000066400000000000000000000004421234107666300206670ustar00rootroot00000000000000\cdbalgorithm{properties}{} Display a list of all available properties. \begin{screen}{1} @properties; ::Accent ::AntiCommuting ::AntiSelfDual ... \end{screen} This list is also available in the graphical notebook interface from the Help menu. \cdbseealgo{algorithms} \cdbseealgo{timing} cadabra-1.39/doc/algorithms/proplist.tex000066400000000000000000000010341234107666300203450ustar00rootroot00000000000000\cdbalgorithm{proplist}{} Show all properties and the patterns to which they are associated. Note that this includes all default properties for objects like {\tt $\backslash prod$}. \begin{screen}{1,2} {A,B}::AntiCommuting. A_{m n}::Symmetric. @proplist; \sum{#}::CommutingAsSum \prod{#}::IndexInherit \prod{#}::Distributable ... {A, B}::AntiCommuting A_{m n}::Symmetric \end{screen} A list of all available properties (not necessarily attached to any object) is instead obtained using \subscommand{properties}. \cdbseealgo{properties} cadabra-1.39/doc/algorithms/quit.tex000066400000000000000000000001551234107666300174560ustar00rootroot00000000000000\cdbalgorithm{quit}{} Exit the program. Any open output file will be flushed and closed. \cdbseealgo{end} cadabra-1.39/doc/algorithms/range.tex000066400000000000000000000012721234107666300175710ustar00rootroot00000000000000\cdbalgorithm{range}{} Replaces a two-element list of integers with the elements in the range, \begin{screen}{1,2,4} {-3,2}; @range(%); \{ -3,-2,-1,0,1,2 \} @range[{1,3}]; \{ 1,2,3 \} \end{screen} When the list has three elements, the algorithm generates a list consisting of a number of copies of the third element of the given list, \begin{screen}{1} @range[{1,3,c}]; {c,c,c}; \end{screen} When the list contains four elements, the first one is used as a counter, and can appear in the fourth element to generate different list elements, \begin{screen}{1} @range[{i, 1, 5, c_{i} }]; { c_1, c_2, c_3, c_4, c_5 }; \end{screen} ~ \cdbseealgo{inner} \cdbseealgo{length} \cdbseealgo{coefficients} cadabra-1.39/doc/algorithms/reduce.tex000066400000000000000000000011421234107666300177400ustar00rootroot00000000000000\cdbalgorithm{reduce}{} {\bf NOT YET FUNCTIONAL} \bigskip Reduce a sum of tensor monomials of the same type, taking into account mono-term as well as multi-term symmetries. This does not aim for a canonical form, but rather for a form in which no monomials occur which can be expressed (using mono- and multi-term symmetries) as a linear combination of other monomials appearing in the sum. An example makes this more clear: \begin{screen}{0,1} {m,n,p,q}::Indices(vector). {m,n,p,q}::Integer(0..10). R_{m n p q}::RiemannTensor. R_{m n q p} R_{m n p q} + R_{m p n q} R_{m n p q}; @reduce!(%); \end{screen} ~ cadabra-1.39/doc/algorithms/reduce_gendelta.tex000066400000000000000000000014041234107666300216040ustar00rootroot00000000000000\cdbalgorithm{reduce\_gendelta}{} Convert generalised delta symbols which contain contracted indices to deltas with fewer indices, according to the formula \begin{equation} n! \, \delta^{a_1\cdots a_n}_{b_1\cdots b_n}\, \delta^{b_1}_{a_1} \cdots \delta^{b_m}_{a_m} = \Big[\prod_{i=1}^m \big( d-(n-i) \big) \Big] \, (n-m)!\, \delta^{a_{m+1}\cdots a_n}_{b_{m+1}\cdots b_n}\, . \end{equation} Here is an example \begin{screen}{1,2} \delta{#}::KroneckerDelta. {m,n,q}::Integer(0..3). \delta_{m}^{n}_{n}^{q}; @reduce_gendelta!(%); (-3/2) \delta_{m}^{q}; \end{screen} Note that this requires that the indices on the Kronecker delta symbol also carry an \subsprop{Integer} property to specify their range. \cdbseeprop{KroneckerDelta} \cdbseeprop{Integer} \cdbseeprop{Indices} cadabra-1.39/doc/algorithms/remove_indexbracket.tex000066400000000000000000000012641234107666300225160ustar00rootroot00000000000000\cdbalgorithm{remove\_indexbracket}{} When a single symbol-with-indices is entered as \begin{screen}{1} (A)_{\mu\nu}; \end{screen} it gets wrapped in an \texcommand{indexbracket} node. In order to remove this node again, and produce \begin{screen}{1} A_{\mu\nu} \end{screen} again, use \subscommand{remove\_indexbracket}. \begin{screen}{1,2} (A)_{\mu\nu}; @remove_indexbracket!(%); A_{\mu\nu}; \end{screen} This algorithm is also useful after the \subscommand{distribute} command has been called on an \texcommand{indexbracket} node which contained a sum; the \subscommand{remove\_indexbracket} will then remove the superfluous brackets around the single symbols. \cdbseealgo{distribute} cadabra-1.39/doc/algorithms/remove_weyl_traces.tex000066400000000000000000000002141234107666300223660ustar00rootroot00000000000000\cdbalgorithm{remove\_weyl\_traces}{} Removes terms containing the trace of a Weyl tensor, i.e.~a Weyl tensor with two indices contracted. cadabra-1.39/doc/algorithms/rename_dummies.tex000066400000000000000000000010231234107666300214610ustar00rootroot00000000000000\cdbalgorithm{rename\_dummies}{} Rename the dummy indices in an expression. This can be necessary in order to make various terms in a sum use the same names for the indices, so that they can be collected. \begin{screen}{1,2,3,5} {m,n,p,q,r,s}::Indices(vector). A_{m n} B_{m n} - A_{p q} B_{p q}; @rename_dummies!(%); A_{m n} B_{m n} - A_{m n} B_{m n}; @collect_terms!(%); 0; \end{screen} Note that the indices need to have been declared as being part of an index list, using the \subsprop{Indices} property. \cdbseeprop{Indices} cadabra-1.39/doc/algorithms/replace_match.tex000066400000000000000000000010641234107666300212630ustar00rootroot00000000000000\cdbalgorithm{replace\_match}{} Replaces a subset of terms in a sum or list which match the given pattern. This is like a substitute, but always acting on entire terms. \begin{screen}{1,2} A + B D G + C D A; @replace_match!(%)( D Q?? -> 1); A + 1; \end{screen} Note the difference with \subscommand{substitute}, \begin{screen}{1,2} A + B D G + C D A; @substitute!(%)( D Q?? -> 1); A + G + A; \end{screen} See \subscommand{take\_match} for further details on how to use this ``select/modify/replace'' mechanism. \cdbseealgo{take_match} \cdbseealgo{substitute} cadabra-1.39/doc/algorithms/reset.tex000066400000000000000000000002231234107666300176120ustar00rootroot00000000000000\cdbalgorithm{reset}{} Erases all expressions and object properties, effectively resetting the program without restarting it. \cdbseealgo{quit} cadabra-1.39/doc/algorithms/rewrite_diracbar.tex000066400000000000000000000011751234107666300220070ustar00rootroot00000000000000\cdbalgorithm{rewrite\_diracbar}{} Rewrite the Dirac conjugate of a product of spinors and gamma matrices as a product of Dirac and hermitean conjugates. This uses \begin{equation} \bar\psi = i \psi^\dagger\Gamma^0\,, \end{equation} together with \begin{equation} \Gamma_m^{\dagger} = \Gamma_0\Gamma_m\Gamma_0 \,. \end{equation} For example, \begin{screen}{1,2,3,4,5} \bar{#}::DiracBar. \psi::Spinor(dimension=10). \Gamma{#}::GammaMatrix. \bar{\Gamma^{m n p} \psi}; @rewrite_diracbar!(%); \bar{\psi} \Gamma^{m n p}; \end{screen} ~ \cdbseealgo{spinorsort} \cdbseeprop{GammaMatrix} \cdbseeprop{DiracBar} \cdbseeprop{Spinor} cadabra-1.39/doc/algorithms/rewrite_indices.tex000066400000000000000000000016621234107666300216570ustar00rootroot00000000000000\cdbalgorithm{rewrite\_indices}{} Rewrite indices on an object by contracting it with a second object which contains indices of both the old and the new type (a vielbein, in other words, or a metric). A vielbein example is \begin{screen}{1,2,3,4} {m,n,p}::Indices(flat). {\mu,\nu,\rho}::Indices(curved). T_{m n p}; @rewrite_indices!(%){ T_{\mu\nu\rho} }{ e_{\mu}^{n} }; T_{\mu \nu \rho} e_{\mu}^{m} e_{\nu}^{n} e_{\rho}^{p}; \end{screen} If you want to raise or lower an index with a metric, this can also be done with as an index rewriting command, as the following example shows: \begin{screen}{1,2,3} {m,n,p,q,r,s}::Indices(curved, position=fixed). H_{m n p}; @rewrite_indices!(%){ H^{m n p} }{ g_{m n} }; H^{q r s} g_{m q} g_{n r} g_{p s}; \end{screen} As these examples show, the desired form of the tensor should be given as the first argument, and the conversion object (metric, vielbein) as the second object. \cdbseealgo{split_index} cadabra-1.39/doc/algorithms/riemann_index_regroup.tex000066400000000000000000000013401234107666300230540ustar00rootroot00000000000000\cdbalgorithm{riemann\_index\_regroup}{} Given a set (or multiple sets) of indices in which to anti-symmetrise, this routine determines whether the indicated Riemann tensor has an index distribution with two of the anti-symmetrised indices on two different pairs. If so, it performs the substitution \begin{equation*} R_{m [p|\, n|q]} \rightarrow \frac{1}{2}R_{m n p q}\, , \end{equation*} which is valid by virtue of the Riccy cyclic identity $R_{m [npq]}=0$. The example above translates to \begin{screen}{1,2,3,4} R_{m n p q}::RiemannTensor. A^{m n}::AntiSymmetric. R_{m p n q} A^{p q}; @riemann_index_regroup!(%); 1/2 R_{m n p q} A^{p q}; \end{screen} Note that this also works on Weyl tensors. \cdbseealgo{young_project_tensor} cadabra-1.39/doc/algorithms/run.tex000066400000000000000000000012101234107666300172710ustar00rootroot00000000000000\cdbalgorithm{run}{} Run an external program on the input expression, replacing it with the standard output of the program. The expression is the first command line argument of the program to be called. Suppose we have a simple script {\tt test.sh} containing \begin{screen}{0} #!/bin/sh echo "$1" | sed -e 's/A/B/g' -e '/;/q' \end{screen} This script replaces 'A' with 'B' in the first command line argument, until it encounters a semi-colon. We can then call this script by using e.g. \begin{screen}{1,2} A B C A D E; @run(%){"./test.sh"}; B B C B D E; \end{screen} The external program should make sure that it produces valid cadabra input. cadabra-1.39/doc/algorithms/spinorsort.tex000066400000000000000000000023301234107666300207130ustar00rootroot00000000000000\cdbalgorithm{spinorsort}{} Sorts Majorana spinor bilinears using the Majorana flip property, which for anti-commuting spinors takes the form \begin{equation} \bar\psi_1 \Gamma_{r_1\cdots r_n}\psi_2 = \alpha \beta^n (-)^{\frac{1}{2}n(n-1)}\, \bar\psi_1 \Gamma_{r_1\cdots r_n}\psi_2\, . \end{equation} Here $\alpha$ and $\beta$ determine the properties of the charge conjugation matrix, \begin{equation} {\cal C}^T = \alpha {\cal C}\,,\quad {\cal C}\Gamma_r {\cal C}^{-1} = \beta \Gamma_r^T\, . \end{equation} Here is an example. \begin{screen}{1,2,3,4,5,6,7} {\chi, \psi, \psi_{m}}::Spinor(dimension=10, type=MajoranaWeyl). {\chi, \psi, \psi_{m}}::AntiCommuting. \bar{#}::DiracBar. \Gamma{#}::GammaMatrix. {\psi_{m}, \psi, \chi}::SortOrder. \bar{\chi} \Gamma_{m n} \psi; @spinorsort!(%); (-1) \bar{\psi} \Gamma_{m n} \chi; \end{screen} ~ % These depend on dimension and are given by (some of these are choices) % \kcomment{KP}{signature dependence!} % \begin{equation} % \begin{matrix} % & \alpha & \beta \\ % d=4 & - & - \\ % d=5 & - & + \\ % d=6,1 & + & - \\ % d=8 & + & - \\ % d=10,1 & - & - % \end{matrix} % \end{equation} \cdbseeprop{GammaMatrix} cadabra-1.39/doc/algorithms/split_index.tex000066400000000000000000000014031234107666300210130ustar00rootroot00000000000000\cdbalgorithm{split\_index}{} Replace a sum by a sum-of-sums, abstractly. Concretely, replaces all index contractions of a given type by a sum of two terms, each with indices of a different type. Useful for Kaluza-Klein reductions and the like. An example makes this more clear: \begin{screen}{1,2,3,4,5,7,8} {M,N,P,Q,R}::Indices(full). {m,n,p,q,r}::Indices(space1). {a,b,c,d,e}::Indices(space2). A_{M p} B_{M p}; @split_index(%){M,m,a}; A_{m p} B_{m p} + A_{a p} B_{a p}; @pop(%); @split_index(%){M,m,4}; A_{m p} B_{m p} + A_{4 p} B_{4 p}; \end{screen} Note that the two index types into wich the original indices should be split can be either symbolic (as in the first case above) or numeric (as in the second case). \cdbseeprop{Indices} \cdbseealgo{rewrite_indices} cadabra-1.39/doc/algorithms/substitute.tex000066400000000000000000000020611234107666300207050ustar00rootroot00000000000000\cdbalgorithm{substitute}{} \label{loc_substitute} Generic substitution command. Takes a rule or a set of rules according to which an expression should be modified. If more than one rule is given, it tries each rule in turn, until the first working one is encountered, after which it continues with the next node. \begin{screen}{1,2} G_{mu nu rho} + F_{mu nu rho}; @substitute!(%)( F_{mu nu rho} -> A_{mu nu} B_{rho} ); G_{mu nu rho} + A_{mu nu} B_{rho}; \end{screen} \begin{screen}{1,2} A_{mu nu} B_{nu rho} C_{rho sigma}; @substitute!(%)( A_{m n} C_{p q} -> D_{m q} ); D_{mu sigma} B_{nu rho}; \end{screen} This command takes full care of dummy index relabelling, as the following example shows: \begin{screen}{1,2,3} {m,n,q,d1,d2,d3,d4}::Indices(vector). a_{m} b_{n}; @substitute!(%)( a_{q} -> c_{m n} d_{m n q} ); c_{d1 d2} * d_{d1 d2 m} * b_{n}; \end{screen} By postfixing a name with a question mark, it becomes a pattern. The substitution algorithm can do very complicated things; for more detailed information on substitution, see the manual. \cdbseealgo{vary} cadabra-1.39/doc/algorithms/sumflatten.tex000066400000000000000000000007731234107666300206640ustar00rootroot00000000000000\cdbalgorithm{sumflatten}{} Removes brackets in a sum, that is, makes changes of the type \begin{equation} a+(b+c) \rightarrow a+b+c\, . \end{equation} In terms of code this reads \begin{screen}{1,2} a + (b + c); @sumflatten!(%); a + b + c; \end{screen} The above is sometimes required because it is possible to write and keep nested sums with brackets, like in the example above, in order to improve readability of expressions. \cdbseealgo{prodflatten} \cdbseealgo{listflatten} \cdbseealgo{distribute} cadabra-1.39/doc/algorithms/sumsort.tex000066400000000000000000000011361234107666300202100ustar00rootroot00000000000000\cdbalgorithm{sumsort}{} Sort terms in a sum, taking into account any \subsprop{SortOrder} properties, or else sorting lexographically. \label{loc_sumsort} This is often useful in case sums appear as exponents; in this case it is necessary to first sort the sums before terms can be collected, as the following example shows. \begin{screen}{1,2,4,5} a**(-1+d) - a**(d-1); @collect_terms!(%); a**(-1+d) - a**(d-1); @sumsort!(%): @collect_terms!(%); 0; \end{screen} For more information on \subsprop{SortOrder} see the documentation of \subscommand{prodsort}. \cdbseealgo{prodsort} \cdbseeprop{SortOrder} cadabra-1.39/doc/algorithms/sym.tex000066400000000000000000000015061234107666300173050ustar00rootroot00000000000000\cdbalgorithm{sym}{} Symmetrise a product or tensor in the indicated objects. This works both with normal objects, as in \begin{screen}{1,2} A B C; @sym!(%){A,B,C}; 1/6 A B C + 1/6 A C B + 1/6 B A C + 1/6 B C A + 1/6 C A B + 1/6 C B A; \end{screen} as well as with indices. When used with indices, remember to also indicate whether you want to symmetrise upper or lower indices, as in the example below. \begin{screen}{1,2} A_{m n} B_{p}; @sym!(%){ _{m}, _{n}, _{p} }; 1/6 A_{m n} B_{p} + 1/6 A_{m p} B_{n} + 1/6 A_{n m} B_{p} + 1/6 A_{n p} B_{m} + 1/6 A_{p m} B_{n} + 1/6 A_{p n} B_{m}; \end{screen} Anti-symmetrisation (i.e.~introducing a sign depending on the permutation of each term) is handled by the \subscommand{asym} algorithm. \cdbseealgo{asym} \cdbseealgo{young_project} \cdbseealgo{young_project_tensor} cadabra-1.39/doc/algorithms/tabcanonicalise.tex000066400000000000000000000012501234107666300216100ustar00rootroot00000000000000\cdbalgorithm{tabcanonicalise}{} Canonicalise a tableau, that is, sort equal-length columns and sort boxes within columns. This algorithm acts on objects with the \subsprop{FilledTableau} property. \begin{screen}{1,2,3} \tableau{#}::FilledTableau. \tableau{b,d}{c,a}; @tabcanonicalise!(%); -\tableau{a,b}{d,c}; \end{screen} This algorithm only uses mono-term symmetries of Young tableaux, i.e.~symmetries which relate the given tableau to one other tableau. Garnir symmetries (generalised Bianchi and Ricci identities) are not handled by \subscommand{tabcanonicalise} but require the use of \subscommand{tabstandardform}. \cdbseeprop{FilledTableau} \cdbseealgo{tabstandardform} cadabra-1.39/doc/algorithms/tabdimension.tex000066400000000000000000000012021234107666300211420ustar00rootroot00000000000000\cdbalgorithm{tabdimension}{} Compute the dimension of the representation corresponding to a tableau or filled tableau. This algorithm acts on objects with the \subsprop{Tableau} or \subsprop{FilledTableau} property, which should have the {\tt dimension} argument set. \begin{screen}{1,2,3,5,6,7} \tableau{#}::Tableau(dimension=10). \tableau{2}{2}; @tabdimension!(%); 825; \tableau{#}::Tableau(dimension=8). \tableau{2}{2}; @tabdimension!(%); 336; \end{screen} The computation uses the standard hook rule. \cdbseeprop{Tableau} \cdbseeprop{FilledTableau} \cdbseealgo{tabdimension} \cdbseealgo{decompose_product} \cdbseealgo{tabcanonicalise} cadabra-1.39/doc/algorithms/tabstandardform.tex000066400000000000000000000012221234107666300216430ustar00rootroot00000000000000\cdbalgorithm{tabstandardform}{} Bring a filled Young tableau to standard form, that is, to a form in which two horizontally adjacent boxes appear in sorted form. This requires the use of Garnir symmetries and generically produces a sum of tableaux. This algorithm acts on objects with the \subsprop{FilledTableau} property. \begin{screen}{1,2,3} \tableau{#}::FilledTableau. \tableau{b,d}{c,a}; @tabstandardform!(%); \tableau{a,c}{b,d} - \tableau{a,b}{c,d}; \end{screen} In the graphical interface this displays as \begin{equation} \ftableau{{a}{c},{b}{d}} - \ftableau{{a}{b},{c}{d}}; \end{equation} \cdbseeprop{FilledTableau} \cdbseealgo{tabcanonicalise} cadabra-1.39/doc/algorithms/take.tex000066400000000000000000000007031234107666300174170ustar00rootroot00000000000000\cdbalgorithm{take}{} Replace a sum, product or list with a subset of its terms, factors or elements. Example, \begin{screen}{1,2,4,5,7,8} A+B+C+D+E; @take(%){1,3}; B+D; {A,B,C,D,E}; @take(%){4}; \{ E \}; A*B*C*D*E; @take(%){2..\infty}; C*D*E; \end{screen} As usual, a range can be open by setting the second boundary to \texcommand{infty}. In order to select terms based on pattern matching, see \subscommand{take\_match} \cdbseealgo{take_match} cadabra-1.39/doc/algorithms/take_match.tex000066400000000000000000000030601234107666300205720ustar00rootroot00000000000000\cdbalgorithm{take\_match}{} Select a subset of terms in a sum or list which match the given pattern. \begin{screen}{1,2} A + B D G + C D A; @take_match(%)( D Q?? ); B D G + C D A; \end{screen} In particular, note that the {\tt Q??} is necessary to ensure that the pattern matches a product of {\tt D} with something else. However, the algorithm has selected the entire term, not just the part matched by the pattern; compare the similar \begin{screen}{1,2} A + B D G + C D A; @substitute!(%)( D Q?? -> 1); A + G + A; \end{screen} in which the replacement is done on the pattern, not on the entire term which contains the pattern. This algorithm is particularly useful in combination with a copy operation on the expression. It allows one to take out certain terms from an expression, do manipulations on it, and then substitute it back using \subscommand{replace\_match}. The following example shows how this works by taking out the term which contains a $\chi$ factor, doing a transformation on the $A_{m n}$ tensor in that term, and then substituting back using \subscommand{replace\_match}. \begin{screen}{1,2,4,5} expr:= A_{m n} \chi B^{m}_{p} + \psi A_{n p}; @take_match[@(%)]( \chi Q?? ); A_{m n} \chi B^{m}_{p}; @substitute!(%)( A_{m n} -> C_{m n} ); @replace_match!(expr)( \chi Q?? -> @(%) ); C_{m n} \chi B^{m}_{p} + \psi A_{n p}; \end{screen} The \subscommand{replace\_match} pattern matching rules are identical to those in \subscommand{take\_match}: a match always matches an entire term, not just a factor of it. \cdbseealgo{replace_match} \cdbseealgo{substitute} cadabra-1.39/doc/algorithms/timing.tex000066400000000000000000000006731234107666300177700ustar00rootroot00000000000000\cdbalgorithm{timing}{} Display a list of all algorithms together with the total time spent in them since program start or since a \subscommand{reset}. \begin{screen}{1} @timing; @ 0 0 sec and 0 microsec @acanonicalorder 0 0 sec and 0 microsec @all_contractions 0 0 sec and 0 microsec ... \end{screen} ~ \cdbseealgo{algorithms} \cdbseealgo{properties} cadabra-1.39/doc/algorithms/tree.tex000066400000000000000000000012051234107666300174300ustar00rootroot00000000000000\cdbalgorithm{tree}{} Display the internal tree form of a given expression. Can be used on a single expression or on an entire tree: \begin{screen}{1,2,3,10} A_{m n}: B_{m n}: @tree(1); (1): \history (0) 1:{\expression} (1) 2: {A} (2) 3: _{m} (3) 4: _{n} (3) 5: \asymimplicit (2) @tree; (1): {\expression} (1) 1: {A} (2) 2: _{m} (3) 3: _{n} (3) 4: \asymimplicit (2) (2): {\expression} (1) 1: {B} (2) 2: _{m} (3) 3: _{n} (3) 4: \asymimplicit (2) \end{screen} Most expressions lead to extremely lengthy output, so it is useful to redirect it to a file using output redirection. cadabra-1.39/doc/algorithms/unique_indices.tex000066400000000000000000000003551234107666300215020ustar00rootroot00000000000000\cdbalgorithm{unique\_indices}{} Make all open indices in a product of tensors unique, taking into account index set declarations. \begin{screen}{1,2} {m,n,p#}::Indices. { A_{m n}, B_{m n}, C_{m n} }; @unique_indices!(%); \end{screen} cadabra-1.39/doc/algorithms/unwrap.tex000066400000000000000000000030001234107666300200000ustar00rootroot00000000000000\cdbalgorithm{unwrap}{} Move objects out of \subsprop{Derivative}s or \subsprop{Accent}s when they do not depend on these operators. Accents will get removed from objects which do not depend on them, as in the following example: \begin{screen}{1,2,3,5,6,8} \hat{#}::Accent. \hat{#}::Distributable. B::Depends(\hat). \hat{A+B+C}: @distribute!(%); \hat{A} + \hat{B} + \hat{C}; @unwrap!(%); A + \hat{B} + C; \end{screen} Derivatives will be set to zero if an object inside does not depend on it. All objects which are annihilated by the derivative operator are moved to the front (taking into account anti-commutativity if necessary), \begin{screen}{1,2,4,5} \partial{#}::PartialDerivative. {A,B,C,D}::AntiCommuting. x::Coordinate. {B,D}::Depends(\partial). \partial_{x}( A B C D ): @unwrap!(%); - A C \partial_{x}{B D}; \end{screen} Note that a product remains inside the derivative; to expand that use \subscommand{prodrule}. Here is another example \begin{screen}{1,2,3,4,6} \del{#}::Derivative. X::Depends(\del). \del{X*Y*Z}: @prodrule!(%); \del{X} * Y * Z + X * \del{Y} * Z + X * Y * \del{Z}; @unwrap!(%); \del{X}*Y*Z; \end{screen} Note that all objects are by default constants for the action of \subsprop{Derivative} operators. If you want objects to stay inside derivative operators you have to explicitly declare that they depend on the derivative operator or on the coordinate with respect to which you take a derivative. \cdbseeprop{Accent} \cdbseeprop{Derivative} \cdbseeprop{PartialDerivative} \cdbseealgo{prodrule} cadabra-1.39/doc/algorithms/vary.tex000066400000000000000000000030201234107666300174470ustar00rootroot00000000000000\cdbalgorithm{vary}{} Generic variation command. Takes a rule or a set of rules according to which the terms in a sum should be varied. In every term, apply the rule once to every factor. \begin{screen}{1,2} A B + A C; @vary(%)( A -> \epsilon D, B -> \epsilon C, C -> \epsilon A - \epsilon B ); \epsilon D B + A \epsilon C + \epsilon D C + A (\epsilon A - \epsilon B); \end{screen} It also works when acting on powers, in which case it will use the product rule to expand them. \begin{screen}{1,2} A**3; @vary(%)( A -> \delta{A} ); 3 A**{2} \delta{A}; \end{screen} This algorithm is thus mostly intended for variational derivatives (subsequent partial integrations can be done using \subscommand{pintegrate}). Note: In the examples above, the command is applied only at the top level (there is no exclamation mark used in the call of \subscommand{vary}). To understand why this is important, compare the following two examples. The first one works as expected, \begin{screen}{1,2} A B; @vary(%)( A -> a, B -> b); a * B + A * b; \end{screen} In the second one, we add an exclamation mark, \begin{screen}{1,2} A B; @vary!(%)( A -> a, B -> b); 0; \end{screen} The reason why we now get a zero is that in the first step, the vary command acts in each of the individual factors, producing \begin{screen}{0} a b; \end{screen} It then acts once more at the level of the product. But now there are no uppercase symbols left anymore, and the variation produces zero. \cdbseealgo{pintegrate} \cdbseealgo{substitute} cadabra-1.39/doc/algorithms/weyl_index_order.tex000066400000000000000000000007221234107666300220360ustar00rootroot00000000000000\cdbalgorithm{weyl\_index\_order}{} Sorts the indices on a \deprecated Riemann or Weyl tensor by first applying anti-symmetry in each pair, and subsequently sorting the pairs by using symmetry under pair exchange. This alphabetical sorting can be prohibited by giving a list of indices which is preferred to be in the first pair. \begin{screen}{1,2,4} R_{s2 s1 s3 r1}; @weyl_index_order(%){s1}; R_{s1 s2 r1 s3} @weyl_index_order(%); R_{r1 s3 s1 s2} \end{screen} ~ cadabra-1.39/doc/algorithms/xterm_title.tex000066400000000000000000000005771234107666300210440ustar00rootroot00000000000000\cdbalgorithm{xterm\_title}{} When the program is running in command-line mode, this command set the title of the xterm to the given argument: \begin{screen}{1,2} @xterm_title{"second part"}; \end{screen} This can be useful to monitor the stages of a long calculation: by putting this command at intermediate stages it becomes easier to spot the current status of a running job. cadabra-1.39/doc/algorithms/young_project.tex000066400000000000000000000017751234107666300213740ustar00rootroot00000000000000\cdbalgorithm{young\_project}{} Project the indicated expression onto a Young tableau representation. This includes the normalisation factor, such that applying the operation twice does not change the result anymore. For example, \begin{screen}{1,2,5,6} A_{m n} B_{p}: @young_project!(%){2,1}{0,1,2}; 1/3 A_{m n} B_{p} + 1/3 A_{n m} B_{p} - 1/3 A_{p n} B_{m} - 1/3 A_{n p} B_{m}; @young_project!(%){2,1}{0,1,2}: @sumflatten!(%): @collect_terms!(%); 1/3 A_{m n} B_{p} + 1/3 A_{n m} B_{p} - 1/3 A_{p n} B_{m} - 1/3 A_{n p} B_{m}; \end{screen} The first argument gives the tableau shape, while the second argument gives the index position associated to each box in the Young tableau (similar to the way in which the \subsprop{TableauSymmetry} property works; note that this algorithm does not require the tensors to have any specific symmetries). The index positions given in the second argument count from zero. \cdbseealgo{young_project_tensor} \cdbseealgo{young_project_product} \cdbseeprop{TableauSymmetry} cadabra-1.39/doc/algorithms/young_project_product.tex000066400000000000000000000013541234107666300231250ustar00rootroot00000000000000\cdbalgorithm{young\_project\_product}{} Project all tensors in a product with their Young tableau projector. Each factor is projected in turn, after which the product is distributed and then canonicalised. This is often faster and more memory-efficient than first projecting every factor and then distributing. Young projection can be used to find equalities between tensor polynomials which are due to multi-term symmetries, such as the Ricci identity in the example below. \begin{screen}{1,2,3,4,5,6} {a,b,c,d}::Indices. R_{a b c d}::RiemannTensor. 2 R_{a b c d} R_{a c b d} - R_{a b c d} R_{a b c d}; @young_project_product!(%); @sumflatten!(%); @collect_terms!(%); 0; \end{screen} ~ \cdbseealgo{decompose} \cdbseealgo{young_project_tensor} cadabra-1.39/doc/algorithms/young_project_tensor.tex000066400000000000000000000023041234107666300227530ustar00rootroot00000000000000\cdbalgorithm{young\_project\_tensor}{} Project tensors with their Young projection operator. This works for simple symmetric or anti-symmetric objects, as in \begin{screen}{1,2,3} A_{m n}::Symmetric. A_{m n} A_{m p}; @young_project_tensor!(%); (1/2 A_{m n} + 1/2 A_{n m}) (1/2 A_{m p} + 1/2 A_{p m}); \end{screen} but more generically works for any tensor which has a \subsprop{TableauSymmetry} property attached to it. \begin{screen}{1,3} A_{m n p}::TableauSymmetry(shape={2,1}, indices={0,2,1}). A_{m n p}; @young_project_tensor!(%); 1/3 A_{m n p} + 1/3 A_{p n m} - 1/3 A_{n m p} - 1/3 A_{p m n}; \end{screen} When the argument {\tt ModuloMonoterm} is added, the resulting expression will be simplified using the monoterm symmetries of the tensor, \begin{screen}{1,3} A_{m n p}::TableauSymmetry(shape={2,1}, indices={0,2,1}). A_{m n p}; @young_project_tensor!(%){ModuloMonoterm}; 2/3 A_{m n p} - 1/3 A_{n p m} + 1/3 A_{m p n}; \end{screen} (in this example, the tensor is anti-symmetric in the indices~0 and 1, hence the simplification compared to the previous example). \cdbseealgo{young_project} \cdbseealgo{young_project_product} \cdbseeprop{TableauSymmetry} \cdbseeprop{Symmetric} \cdbseeprop{AntiSymmetric} cadabra-1.39/doc/amazing000066400000000000000000000007441234107666300151560ustar00rootroot00000000000000http://www.codeproject.com/KB/architecture/composite_visitor.aspx "Separately, and the subject topic remains appropriate, I wonder if Kasper Peeters could be persuaded to revise the licence terms of his stl-like tree, which he is still maintaining - at the Max Planck institute no less. I used to code commercially and feel it is a pity if academics restrict their work to, essentially, other academics, especially if they are in part supported by income tax." Dafydd, 18-feb-2006 cadabra-1.39/doc/cadabra.sty000066400000000000000000000026471234107666300157270ustar00rootroot00000000000000\usepackage{amsmath} \usepackage{amssymb} \usepackage{bbold} \usepackage{fancyvrb} \usepackage{relsize} \newcommand{\cdbproperty}[2]{property: {\bfseries\large ::#1{\small \if!#2!\else(#2)\fi}}\par} \newcommand{\cdbalgorithm}[2]{algorithm: {\bfseries\large @#1}\par} \newcommand{\cdbreserved}[2]{reserved: {\bfseries\large $\backslash$#1}\par} \newcommand{\cdbseealgo}[1]{} \newcommand{\cdbseeprop}[1]{} \newcommand{\subscommand}[1]{@{#1}} \newcommand{\inertcommand}[1]{{\tt @@#1}} \newcommand{\texcommand}[1]{{\tt $\backslash$#1}} \newcommand{\subsprop}[1]{{\tt #1}} \newcommand{\Cdb}{Cadabra{}} % Additional operators \DeclareMathOperator{\sgn}{sgn} % Screen environment, for display of verbatim material. \makeatletter \fvset{frame=lines,framerule=0.1pt,framesep=6pt,numbers=none,xleftmargin=5ex,fontfamily=tt,fontsize=\small} \newenvironment{screen}[1]{\hilitelines(#1)\color[named]{Blue}\Verbatim}{\endVerbatim\color[named]{Black}} \makeatother \newif\ifhilite \def\hilitelines(#1){% \def\FancyVerbFormatLine##1{% \def\fancylineinput{##1}% \hilitefalse \splitfirst #1,\relax,% \ifhilite\else \fancylineinput \fi}} \def\splitfirst#1,{% \ifx\relax#1\empty\else \hiliteline{#1}{\fancylineinput}\expandafter\splitfirst \fi} \def\hiliteline#1#2{% \ifhilite\else \ifnum\value{FancyVerbLine} = #1 \llap{{\smaller\smaller \raisebox{.8ex}{$\vartriangleright$}}\,\,\,}% \fi \fi} cadabra-1.39/doc/cadabra.tex000066400000000000000000004503511234107666300157070ustar00rootroot00000000000000\documentclass[11pt]{article} \usepackage[textwidth=420pt,textheight=650pt,headheight=13.6pt,nofoot,includehead]{geometry} \usepackage{bm} \usepackage{amsmath} \usepackage{amssymb} \usepackage[colorlinks=true, citecolor=red, linkcolor=blue, urlcolor=red, plainpages=false, pdfpagelabels]{hyperref} \usepackage{relsize} \usepackage{xspace} \usepackage{multicol} \usepackage{nomencl} \usepackage{titlesec} \usepackage{titletoc} \usepackage[bottom]{footmisc} \usepackage{makeidx} \usepackage{charter} \usepackage{textfit} \usepackage[numbers,sort&compress]{natbib} \usepackage{hypernat} \usepackage{fancyhdr} \usepackage{fancyvrb} \usepackage{bbold} \usepackage[usenames]{color} \usepackage{caption} \renewcommand\captionlabelfont{\footnotesize\upshape\bfseries} \renewcommand\captionfont{\footnotesize} \makeindex \usepackage{tableaux} \newcommand{\dcite}[1]{{\citeauthor{#1}~\cite{#1}}} \newcommand{\ddcite}[2]{{\citeauthor{#1}~\cite{#1,#2}}} \setlength{\skip\footins}{15pt plus 4pt minus 2 pt} \DeclareMathOperator{\sgn}{sgn} % Screen environment, for display of verbatim material. \makeatletter \newcommand{\kcomment}[2]{{\bf [#1: #2]}} \newcommand{\bfcomment}[2]{{\bf [#1: #2]}} \newcommand{\outdated}{{\bfseries (documentation no longer correct!)}} \fvset{frame=lines,framerule=0.1pt,framesep=6pt,numbers=none,xleftmargin=5ex,fontfamily=tt,fontsize=\small} \newenvironment{screen}[1]{\hilitelines(#1)\Verbatim}{\endVerbatim} \makeatother \newif\ifhilite \def\hilitelines(#1){% \def\FancyVerbFormatLine##1{% \def\fancylineinput{##1}% \hilitefalse \splitfirst #1,\relax,% \ifhilite\else \fancylineinput \fi}} \def\splitfirst#1,{% \ifx\relax#1\empty\else \hiliteline{#1}{\fancylineinput}\expandafter\splitfirst \fi} \def\hiliteline#1#2{% \ifhilite\else \ifnum\value{FancyVerbLine} = #1 \llap{{\smaller\smaller \raisebox{.8ex}{$\vartriangleright$}}\,\,\,}% \fi \fi} % \colourcmd{#2}\hilitetrue %\def\colourcmd{\colorbox{red}} % List layout. \makenomenclature %glossary \setlength{\nomitemsep}{-\parsep} %\renewcommand{\nomname}{\hspace{-3mm}\raisebox{3.2mm}{\hbox{\normalsize\it % % List of algorithms and properties:}}\vspace{-7mm}} \renewcommand{\nomname}{\vspace{-17mm}} \renewcommand{\nomlabel}[1]{{\tt \def\cdbat{@}\def\cdbcc{::}\def\cdbbs{$\backslash$}#1}\hfill} \renewcommand{\pagedeclaration}[1]{#1~~~} \renewcommand\descriptionlabel[1]{\hbox to \textwidth{\quad\quad\bf {#1}\hfill}} \newcommand{\cdb}{{cadabra}\xspace} \newcommand{\Cdb}{{Cadabra}\xspace} \newcommand{\Cpp}{\leavevmode\rm{\hbox{C\hskip -0.1ex\raise 0.5ex\hbox{\tiny ++}}}\xspace} % Three macros to declare the main usage of a command, property or % member function (to appear in the table of contents of the module % section), and commands to use for every subsequent use in the % text (which may at some stage end up in the index at the end). \newcommand{\cdbcommand}[2]{\nomenclature{\cdbat#1}{\hfill\nomrefpage}{\tt @#1}} \newcommand{\subscommand}[1]{{\tt @#1}} \newcommand{\cdbprop}[2]{\nomenclature{\cdbcc#1}{\hfill\nomrefpage}{\tt ::#1}} \newenvironment{props}{\par\noindent{\bf properties:}\description}{\enddescription} \newenvironment{algs}{\par\noindent{\bf algorithms:}\description}{\enddescription} \newenvironment{reserved}{\par\noindent\description}{\enddescription} %\newenvironment{props}{\par\noindent{\bf properties:}\\[1ex]}{\bigskip\par} %\newenvironment{algs}{\par\noindent{\bf algorithms:}\\[1ex]}{\bigskip\par} \newcommand{\cdbalgorithm}[2]{\nomenclature{\cdbat#1}{\hfill\nomrefpage}\item[{\tt @#1}]} \newcommand{\cdbproperty}[2]{\nomenclature{\cdbcc#1}{\hfill\nomrefpage}\item[{\tt ::#1}\if!#2!\else(#2)\fi]} \newcommand{\cdbreserved}[2]{\nomenclature{\cdbbs#1}{\hfill\nomrefpage}\item[{\tt $\backslash$#1}\if!#2!\else\{#2\}\fi]} %\newcommand{\cdbalgorithm}[2]{\nomenclature{\cdbat#1}{\hfill\refpage}\noindent{\tt @#1}\\} %\newcommand{\cdbproperty}[2]{\nomenclature{\cdbcc#1}{\hfill\refpage}\noindent{\tt ::#1}\if#2{}\else(#2)\fi} \newcommand{\cdbseealgo}[1]{} \newcommand{\cdbseeprop}[1]{} \newcommand{\subsprop}[1]{{\tt #1}} \newcommand{\cdbclass}[1]{{\tt #1}} \newcommand{\cdbfile}[1]{{\tt #1}} \newcommand{\member}[1]{{\tt #1}} \newcommand{\subsmember}[1]{{\tt #1}} \newcommand{\deprecated}{\marginpar{{\bf\smaller deprecated}}} \newcommand{\inertcommand}[1]{{\tt @@#1}} \newcommand{\texcommand}[1]{{\tt $\backslash$#1}} \newcommand{\ctri}{{\smaller\smaller$\blacktriangleright$}} \newcommand{\boolargs}{{\it true\/}$|${\it false\/}} \newcommand{\listargs}{{\it expression list\/}} \numberwithin{equation}{section} \def\mystrut{\vbox to 8.5pt{}\vtop to 3.5pt{}} \def\V{\hskip10pt\vrule\hskip10pt} \def\T{\hskip10pt\vrule\vrule height2.5pt depth -2.1pt width 10pt} \def\L{\hskip10pt\vrule height 8.5pt depth -2.1pt \vrule height2.5pt depth -2.1pt width 10pt} \def\N{\hskip10pt\phantom{\vrule}\hskip10pt} \def\hw{\hskip-1000pt plus 1fil} % Courtesy of Donald Arsenau. \makeatletter \newenvironment{descerate} {\enumerate \@noitemargtrue \let\@noitemargfalse\relax \renewcommand\makelabel[1]{% \hspace\labelwidth \llap{\@itemlabel}% \hspace\labelsep \textbf{##1}% }% }% {\endenumerate} \makeatother %\renewcommand{\contentsname}{\vspace{-3ex}} % Page layout style % \pagestyle{fancy} \renewcommand{\sectionmark}[1]{\markboth{{\it\small #1}}{}}% \renewcommand{\subsectionmark}[1]{\markboth{{\it\small \thesubsection.~#1}}{}}% \fancyhf{}% \fancyhead[L]{\leftmark\hspace{3cm}} \fancyhead[R]{\thepage}% \renewcommand{\headrulewidth}{.1pt} \renewcommand{\footrulewidth}{0pt} \fancypagestyle{plain}{% \fancyhead{} } %\newcommand{\sectionformat}[1]{\colorbox[rgb]{.84,.84,.95}{$\vcenter to 2.5ex{\vspace{-.45ex}\hbox % to 444pt{\bfseries\textcolor[rgb]{0,0,0}{\Huge\bfseries \hspace{3mm}#1\strut\hfill}}}$}} %\newcommand{\subsectionformat}[1]{\colorbox[rgb]{.9,.9,.98}{$\vcenter to 1.5ex{\hbox % to 444pt{\bfseries\textcolor[rgb]{0,0,0}{\large\bfseries \hspace{3mm}\thesubsection~~#1\strut\hfill}}}$}} \newcommand{\sectionformat}[1]{\Huge\bfseries \hspace{3mm}#1} \newcommand{\subsectionformat}[1]{\large\bfseries \hspace{3mm}\thesubsection~~#1} % \titlecontents{section}[0pt]{\addvspace{1pc}\itshape}% % {\contentsmargin{0pt}\bfseries% % \makebox[0pt][r]{\large\thecontentslabel\enspace}\large}% % {\contentsmargin{0pt}\large} % {\quad\thepage}[\addvspace{.5pc}] \renewcommand{\contentsname}{\hspace{-30pt}Table of Contents} \titleformat{\section}[block] {\normalfont\bfseries}{}{-30pt}{\sectionformat} \titleformat{\subsection}[block] {\bfseries}{}{-30pt}{\subsectionformat} \begin{document} \pagestyle{empty} \begin{flushright} original: July 2006\\ this version: November 2nd, 2012\\ AEI-2006-038 \end{flushright} \vspace{6ex} \hspace{-3mm}{\bf \scaletowidth{7cm}{Cadabra}}~\\[.8ex] {\it A field-theory motivated approach to symbolic computer algebra}\\[6ex] {\large\bf Copyright \copyright~2001--2012 ~Kasper Peeters}\\[25ex] {\huge\bf Tutorial and reference guide} \vfill \noindent {\smaller This manual is available under the terms of the GNU Free Documentation License, version 1.2.\\ The accompanying software is available under the terms of the GNU General Public License, version 2.} \newpage \pagestyle{fancy} \noindent \Cdb is a computer algebra system for the manipulation of tensorial mathematical expressions such as they occur in ``field theory problems''. It is aimed at, but not necessarily restricted to, high-energy physicists. It is constructed as a simple tree-manipulating core, a large collection of standalone algorithmic modules which act on the expression tree, and a set of modules responsible for output of nodes in the tree. All of these parts are written in \Cpp. The input and output formats closely follow \TeX, which in many cases means that \cdb is much simpler to use than other similar programs. It intentionally does not contain its own programming language; instead, new functionality is added by writing new modules in \Cpp.\\[2ex] This document contains a description of the core program as well as a detailed listing of the functionality of the currently available algorithm modules. Given the origin of \cdb, the bias is currently towards algorithms for problems in (quantum) field theory, general relativity, group theory and related areas. The last part of this text consists of a user guide on how to implement new algorithmic and display modules and thereby extend the functionality of \cdb.\\[3ex] The software is available for download under the terms of the GNU General Public License from \url{http://cadabra.phi-sci.com/} .\\[3ex] \noindent A paper introducing \cdb to high-energy physicists is available as \begin{center} \begin{minipage}{.8\textwidth} ``\emph{Introducing Cadabra: a symbolic computer algebra system for\\ field theory problems}'',\\ Kasper Peeters, also available as preprint {\tt hep-th/0701238}. \end{minipage} \end{center} Furthermore, a short paper describing the motivation and key technical aspects of \cdb is available as \begin{center} \begin{minipage}{.8\textwidth} ``\emph{A field-theory motivated approach to symbolic computer algebra}'',\\ Kasper Peeters,\\ \emph{Comp.~Phys.~Comm.}~{\bf 176} (2007) 550-558 (title changed in print),\\ {\tt cs.CS/0608005}.\\ \end{minipage} \end{center} If you use \cdb in your own work, please cite these two papers. \vfill \noindent {\large\bf Copyright \copyright~2001--2012 ~Kasper Peeters}\\[3ex] \url{http://maths.dur.ac.uk/users/kasper.peeters/}\\[1ex] \url{mailto:kasper.peeters@gmail.com} \newpage \pagestyle{empty} \tableofcontents \cleardoublepage \pagestyle{fancy} \section{Overview and motivation} % http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&selm=281120021009129275%25sowell2%40cox.net % \begin{flushright} {\smaller\smaller ``\,}\begin{minipage}[t]{220pt} \smaller\smaller{\it I think that several of you are missing the obvious. The majority of people use these programs as symbolic calculators -- occasionally. As such they want their input and output to match what they would have written with pencil and paper.''}~ \hfill {\tt soft-sys.math.maple},~2002 \end{minipage} \end{flushright} % %------------ % % Things to be stressed here: % % - Declaring a variable to be equal to something else and % automatically substituting this something else for every % occurence of the variable are two different things. You % want to be able to write % % W_{m} -> A_{m n} C^{n}; % % W_{m}; % @(W_{m}); % % or something like that. Aha erlebnis: yes, we will do it this % way... % % - Intro: % % - tensor expressions not trees, taking this into account afterwards is kludgy % (automatic dummy index renaming, canonicalisation of expressions, % handling of 'indexbracket' constructions; see the RuleUnique % hack in MathTensor). % - property lists are an essential ingredient in writing compact mathematical % notation. They should be builtin, rather than added in the user-space language, % because the algorithms need this property information. % - tensor expressions are not naturally written in functional notation. % - many _programming_ problems are not easiest to solve in Math or % Maple language; a system that has open internals is required. \noindent \Cdb is a computer algebra system for the manipulation of what could loosely be called \emph{tensorial expressions}. It is aimed at, but not necessarily restricted to, theoretical high-energy physicists. The program's interface, storage system and underlying philosophy differ substantially from other computer algebra systems. Its main characteristics are: \begin{itemize} \item[\ctri] Usage of \TeX{} notation for both input and output, which eliminates many errors in transcribing problems from paper to computer and back. \item[\ctri] Built-in understanding of dummy indices and dummy symbols, including their automatic relabelling when necessary. Powerful algorithms for canonicalisation of objects with index symmetries, both mono-term and multi-term. \item[\ctri] A new way to deal with products of non-commuting objects, enabling a notation which is identical to standard physicist's notation (i.e.~no need for special non-commuting product operators). \item[\ctri] A flexible way to associate meaning (``type information'') to tensors by attaching them to ``properties''. \item[\ctri] An optional unlimited undo system. Interactive calculations can be undone to arbitrary level without requiring a full re-evaluation of the entire calculation. \item[\ctri] A simple and documented way to add new algorithms in the form of \Cpp modules, which directly operate on the internal expression tree. \item[\ctri] A command line interface as well as a graphical one, and a \TeX{}macs frontend. \end{itemize} % There is a certain (large) class of problems in high-energy physics, % often classified as ``simple but tedious algebra'', for which existing % computer algebra systems are not very well suited. The most annoying % issues are typically related to the conversion of the physics problem % into computer language, and to the handling of expressions with many, % often implicit indices of various types. \Cdb differs in essential % aspects from other systems, to take away these problems. The program % is somewhere in the middle between a general purpose system like % Mathematica and programs specialised for very particular tasks. % \medskip % The design of \cdb borrows many ideas from other computer algebra % programs. The user interface was inspired to some extent by % H\"oglund's {\tt Tensign}~\cite{hogl1}. Another source of ideas, in % particular concerning the interactive user interface and the ``formula % history'' was the program {\tt Abra}, written by de Roo. The idea of % using \Cpp as the implementation language for algorithms (rather than % a home-brew language like most computer algebra systems do, or a % variant of LISP) can also be found in {\tt GiNaC}, written by % \dcite{e_baue1}. The use of one generic internal representation can % also be found in {\tt Mathematica} and in fact most LISP-like systems, % although the one used by \cdb is more tuned towards flexibility for % the user. Some ideas about symbols being a-priori separate from their % meaning can also be found in {\tt Yacas} by~\dcite{e_pink1} and this % has to some extent been implemented as ``domains'' in {\tt MuPAD}. % Finally, several of the modules were inspired by existing % software. For the manipulation of gamma matrix algebra, I have % borrowed from {\tt GAMMA} by \dcite{Gran:2001yh} as well as {\tt % Abra}. The general relativity module uses many ideas of the {\tt % GRtensorII} software by~\dcite{e_grte1}. % \medskip This document contains a small tutorial, an extensive reference guide and a technical summary of the program's internals together with a guide on how to write new algorithm modules in \Cpp. %Still discuss: Theorist (now Live Math Maker)~\dcite{http://www.livemath.com/} %which has a mouse-based interface. % %\url{http://poisson.dm.unipi.it/~cerulli/LAlgebrista/its2000.php?lang=en} % % Tensorial for mathematica: % http://home.earthlink.net/~djmp/Mathematica.html % See also the 'expression manipulation' thing there. \vfill \noindent\begin{minipage}{\textwidth} \noindent {\bfseries\large Acknowledgements} \medskip \noindent This program uses code written by several other people. The tensor monomial canonicalisation routines rely on the {\tt xPerm} code written by Jos\'e Martin-Garcia~\cite{e_xact}). All representation-theory related problems are handled by the {\tt LiE} software by Marc van Leeuwen, Arjeh Cohen and Bert Lisser~\cite{e_cohe1}. \medskip \noindent The name \Cdb is an implicit acknowledgement to Mees de Roo, who introduced me to his (so far unpublished) Pascal program {\tt Abra} in the fall of 2000. This program has an extremely physicist-friendly way of dealing with fermions and tensor symmetries, and a formula history mechanism still not found in any other comparable computer algebra system. \Cdb was originally planned to be ``my private \Cpp version of {\tt Abra}'', and even though it does not show much similarity anymore, the development was to a large extent inspired by {\tt Abra}. \end{minipage} \eject \section{Tutorial} The best way to explain the advantages of a new computer algebra system is to demonstrate its ease-of-use for a real-world problem. But if you lack the patience to even read the tutorial on the next few pages, at least read the remainder of this page for an absolute minimum of information. All input in the examples is prefixed with a ``$\vartriangleright$'' symbol. \begin{itemize} \item[\ctri] Start the program by typing ``{\tt prompt cadabra}''. Quit with the ``\subscommand{quit}'' command. \item[\ctri] Tensor expressions are entered as in \TeX{}, with subscripts and superscripts as you know them, e.g. \begin{screen}{1} A_{m n} B^{m q} R^{n}_{q}; \end{screen} Input lines are terminated with ``;'', ``:'' or ``.'' punctuation; see section~\ref{s:input_format} on page~\pageref{s:input_format} for information on what these characters mean. \item[\ctri] Tensors carry properties, such as ``being a Riemann tensor''. These properties are attached by using a double-double dot notation, \begin{screen}{1,2,3} R_{m n p q}::RiemannTensor. g_{m n}::Metric. \psi::Spinor. \end{screen} A list of all properties and the place where they are described in this manual can be found on page~\pageref{s:modules}. \item[\ctri] For many operations \cdb needs to know about the names which it can use for `dummy' indices. You declare dummy indices as \begin{screen}{1} {m,n,p,q}::Indices(vector). \end{screen} where ``{\tt vector}'' is a chosen name for this index set. See section~\ref{s:automaticdummies} on page~\pageref{s:automaticdummies}. \item[\ctri] For many other operators, \cdb needs to know the range over which indices run. Set these index ranges by attaching the \subsprop{Integer} property to the indices, e.g. \begin{screen}{1} {m,n,p,q}::Integer(0..10). \end{screen} \item[\ctri] Expressions can be given a label so you can refer to them again later; you do this by writing the label before the expression and a ``:='' in between, \begin{screen}{1} MaxwellEom:= \diff{F^{m n}}_{n} = 0; \end{screen} \item[\ctri] All things starting with `@' are commands (also called ``active nodes''). Some of the frequently used commands are \subscommand{substitute} (page~\pageref{loc_substitute}), \subscommand{canonicalise} (page~\pageref{loc_canonicalise}) and \subscommand{collect\_terms} (page~\pageref{loc_collect_terms}). \end{itemize} \eject % \subsection{Kaluza-Klein gravity} % % Starting from the Einstein-Hilbert action in four dimensions, a % reduction on a circle produces a theory in three dimensions which % contains two vector fields (one from the Kaluza-Klein vector and one % from the dualised Kaluza-Klein scalar). % % The interactive form of the program is started using the command % \begin{screen}{0} % prompt cadabra % \end{screen} % This produces a startup message and a prompt. We will go through a % simple example in general relativity to get used to the program. % First, we associate properties to the symbols which we will use: % \begin{screen}{0} % m::Integer(0..d-1). % n::Integer(0..d-1). % g_{m n}::Metric. % \Gamma^{m}_{n p}::ChristoffelSymbol. % R_{m n p q}::RiemannTensor. % \end{screen} % In these expressions, the symbols {\tt Integer}, {\tt % ChristoffelSymbol} and {\tt RiemannTensor} are so-called % ``properties'', which are known to \cdb. A list of all known % properties can be found in section~\ref{s:modules}. They are always % associated to names by using the ``::'' notation. The names to which % we associate these properties are arbitrary and we could have % e.g.~used a different symbol to denote a Riemann tensor. For more on % the input format, see section~\ref{s:input_format}. % % % % (for more on the way in which active nodes act, see section~\ref{s:active_nodes}). % % (this algorithm is provided by one of the many separate modules, see % section~\ref{s:modules} for a description of the ones presently available). % \subsection{Web tutorials and sample notebooks} Apart from the tutorials listed below, there is a growing collection of sample notebooks available on the \cdb web site. In addition, help is available through the mailing list. \subsection{Tutorial 1: Tensor monomials and multi-term symmetries} \Cdb contains powerful algorithms to bring any tensorial expression into a canonical form. For multi-term symmetries, \cdb relies on Young tableau methods to generate a canonical form for tensor monomials. \footnote{The user interface for multi-term symmetries is under active development and will simplify substantially in upcoming releases.} As an example, consider the identity \begin{multline} W_{p q r s} W_{p t r u} W_{t v q w} W_{u v s w} - W_{p q r s} W_{p q t u} W_{r v t w} W_{s v u w} \\[1ex] = W_{m n a b} W_{n p b c} W_{m s c d} W_{s p d a} - \frac{1}{4} W_{m n a b} W_{p s b a} W_{m p c d} W_{n s d c}\,. \end{multline} in which~$W_{m n p q}$ is a Weyl tensor (all contracted indices have been written as subscripts for easier readability). Proving this identity requires multiple uses of the Ricci cyclic identity, \begin{equation} W_{m [n p q]} = 0 \,. \end{equation} With \cdb's Young tableau methods the proof is simple. We first declare our objects and input the identity which we want to prove, \begin{screen}{1,2,4} {m,n,p,q,r,s,t,u,v,w,a,b,c,d,e,f}::Indices(vector). W_{m n p q}::WeylTensor. W_{p q r s} W_{p t r u} W_{t v q w} W_{u v s w} - W_{p q r s} W_{p q t u} W_{r v t w} W_{s v u w} - W_{m n a b} W_{n p b c} W_{m s c d} W_{s p d a} + (1/4) W_{m n a b} W_{p s b a} W_{m p c d} W_{n s d c}; \end{screen} Using a Young projector to project all Weyl tensors onto a form which shows the Ricci symmetry in manifest form is done with \hilitelines(0) \begin{screen}{1} @young_project_tensor!(%){ModuloMonoterm}; \end{screen} This algorithm knows that the Weyl tensor sits in the~$\displaystyle\tilde{\tableau{2 2}}$ representation of the rotation group~SO($d$), and effectively leads to a replacement \begin{equation} W_{m n p q} \rightarrow \frac{2}{3} W_{m n p q} - \frac{1}{3} W_{m q n p} + \frac{1}{3} W_{m p n q}\,. \end{equation} We then expand the products of sums and canonicalise using mono-term symmetries, \begin{screen}{1,2,3,4} @distribute!(%): @canonicalise!(%): @rename_dummies!(%): @collect_terms!(%); \end{screen} The last line produces the expected ``zero''. A slightly more complicated multi-term example can be found in \TeX{}macs format in {\tt texmacs/showcase1.tm}. \subsection{Tutorial 2: Tensor monomials, part two} It is easy to generate complete bases of tensor monomials, for any arbitrary tensors (not necessarily for tensors in irreps, as in the previous example). As an example, let us show how this works for a basis constructed from three powers of the Riemann tensor. All that is required is \begin{screen}{1,2,4,6,7} {m,n,p,q,r,s,t,u,v,w,a,b}::Indices(vector). {m,n,p,q,r,s,t,u,v,w,a,b}::Integer(0..9). R_{m n p q}::RiemannTensor. basisR3:= R_{m n p q} R_{r s t u} R_{v w a b}; @all_contractions(%); \end{screen} The result can be further simplified using \begin{screen}{1,2,3,4,5} @canonicalise!(%): @substitute!(%)( R_{m n m n} -> R ): @substitute!(%)( R_{m n m p} -> R_{n p} ): @substitute!(%)( R_{n m p m} -> R_{n p} ): @substitute!(%)( R_{n m m p} -> R_{n p} ); \end{screen} which leads something like\footnote{The algorithm involves a random step which implies that the basis is not always the same, though it is always complete. Further improvements are in preparation which will eliminate this randomness (and also lead to a speedup).} \begin{screen}{0} basisR3:= \{ R_{m n p q} * R_{m p r s} * R_{n r q s}, R * R_{q r} * R_{q r}, R_{n p} * R_{n q p r} * R_{q r}, R_{n p} * R_{n q r s} * R_{p r q s}, R * R_{p q r s} * R_{p q r s}, R_{n p} * R_{n r} * R_{p r}, R_{m n p q} * R_{m r p s} * R_{n r q s}, R * R * R \}; \end{screen} This result is equivalent to the basis given in the ``${\cal R}^0_{6,3}$'' table on page~1184 of~\cite{Fulling:1992vm}. \subsection{Tutorial 3: World-sheet supersymmetry} \label{s:tut_worldsheet} \Cdb not only deals with bosonic tensors, but also with fermionic objects, i.e.~anti-commuting variables. A simple example on which to illustrate their use is the Ramond-Neveu-Schwarz superstring action. We will here show how one uses \cdb to show invariance of this action under supersymmetry (a calculation which is easy to do by hand, but illustrates several aspects of \cdb nicely). We will use a conformal gauge and complex coordinates. We first define the properties of all the symbols which we will use, \begin{screen}{1,2,3,4,5} {\del{#}, \delbar{#}}::Derivative. {\Psi_\mu, \Psibar_\mu, \eps, \epsbar}::AntiCommuting. {\Psi_\mu, \Psibar_\mu, \eps, \epsbar}::SelfAntiCommuting. {\Psi_\mu, \Psibar_\mu, X_\mu}::Depends(\del,\delbar). {\Psi_\mu, \Psibar_\mu, \eps, \epsbar, X_\mu, i}::SortOrder. \end{screen} All objects are by default commuting, so the bosons do not have to be declared separately. You can at any time get a list of the declared properties by using the command \subscommand{proplist}. If you try this example in the graphical front-end, \verb|\\del|, \verb|\\eps| and so on would not print correctly as these are not valid \LaTeX{} symbols. However, you can tell \cdb to print such symbols by using the \subsprop{LaTeXForm} property, \begin{screen}{1,2,3,4,5} \del{#}::LaTeXForm("\partial"). \delbar{#}::LaTeXForm("\bar{\partial}"). \eps::LaTeXForm("\epsilon"). \epsbar::LaTeXForm("\bar{\epsilon}"). \Psibar{#}::LaTeXForm("\bar{\Psi}"). \end{screen} If you use the command-line version, these \subsprop{LaTeXForm} properties are not needed. Now we have to input the action density (see~\cite{kas_kystring} for the conventions used here) \begin{screen}{1} action:= \del{X_\mu} \delbar{X_\mu} + i \Psi_\mu \delbar{\Psi_\mu} + i \Psibar_\mu \del{\Psibar_\mu}; \end{screen} Observe how we wrapped the \texcommand{del} and \texcommand{delbar} operators around the objects on which they are supposed to act. We are now ready to perform the supersymmetry transformation. This is done by using the \subscommand{vary} algorithm, \begin{screen}{1,5,6} @vary(%)( X_\mu -> i \epsbar \Psi_\mu + i \eps \Psibar_\mu, \Psi_\mu -> - \epsbar \del{X_\mu}, \Psibar_\mu -> - \eps \delbar{X_\mu} ); @distribute!(%); @prodrule!(%); \end{screen} The \subscommand{prodrule} command has applied the Leibnitz rule on the derivatives, so that the derivative of a product becomes a sum of terms. We expand again the products of sums, and use \subscommand{unwrap} to take everything out of the derivatives which does not depend on it, \begin{screen}{1,2,3} @distribute!(%); @unwrap!(%); @prodsort!(%); \end{screen} At this stage we are left with an expression which still contains double derivatives. In order to write this in a canonical form, we eliminate all double derivatives by doing one partial integration. This is done by first marking the derivatives which we want to partially integrate, and then using \subscommand{pintegrate}, \begin{screen}{1,2,3,4,5,6,7,8,9,10} @substitute!(%)( \del{\delbar{X_{\mu}}} -> \pdelbar{\del{X_{\mu}}} ): @substitute!(%)( \delbar{\del{X_{\mu}}} -> \pdel{\delbar{X_{\mu}}} ): @pintegrate!(%){ \pdelbar }: @pintegrate!(%){ \pdel }: @rename!(%){"\pdelbar"}{"\delbar"}: @rename!(%){"\pdel"}{"\del"}; @prodrule!(%); @distribute!(%); @unwrap!(%); @prodsort!(%); \end{screen} Notice how, after the partial integration, we renamed the partially integrated derivatives back to normal ones (and again apply Leibnitz' rule). If we now collect terms, \begin{screen}{1} @collect_terms!(%); \end{screen} we indeed find that the total susy variation vanishes. \subsection{Tutorial 4: Super-Maxwell} The following example illustrates the use of a somewhat more complicated set of object properties. A \TeX{}macs version of this problem can be found in the distribution tarball in the file {\tt texmacs/showcase3.tm}. We start with the super-Maxwell action, given by \begin{equation} S = \int\!{\rm d^4}x\, \Big[ -\frac{1}{4} (F_{ab})^2 - \frac{1}{2}\bar{\lambda}\gamma^a \partial_a \lambda\Big]\,, \end{equation} It is supposed to be invariant under the transformations \begin{equation} \delta A_a = \bar{\epsilon}\gamma_a \lambda\,,\quad \delta \lambda = -\frac{1}{2} \gamma^{a b} \epsilon\, F_{a b}\,. \end{equation} The object properties for this problem are \begin{screen}{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15} { a,b,c,d,e }::Indices(vector). \bar{#}::DiracBar. { \partial{#}, \ppartial{#} }::PartialDerivative. { A_{a}, f_{a b} }::Depends(\partial, \ppartial). { \epsilon, \gamma_{#} }::Depends(\bar). \lambda::Depends(\bar, \partial). { \lambda, \gamma_{#} }::NonCommuting. { \lambda, \epsilon }::Spinor(dimension=4, type=Majorana). { \epsilon, \lambda }::SortOrder. { \epsilon, \lambda }::AntiCommuting. \lambda::SelfAntiCommuting. \gamma_{#}::GammaMatrix(metric=\delta). \delta{#}::Accent. f_{a b}::AntiSymmetric. \delta_{a b}::KroneckerDelta. \end{screen} Note the use of two types of properties: those which apply to a single object, like {\tt Depends}, and those which are associated to a list of objects, like {\tt AntiCommuting}. Clearly $\partial_a \lambda$ and $\bar{\epsilon}$ are anti-commuting too, but the program figures this out automatically from the fact that {\tt $\backslash$partial} has an associated {\tt PartialDerivative} property associated to it.\footnote{This is similar to Macsyma's types and features: the property which is attached to a symbol is like a `type', while all properties which the symbol inherits from child nodes are like `features'.} The actual calculation is an almost direct transcription of the formulas above. First we define the supersymmetry transformation rules, \begin{screen}{1} susy:= { \delta{A_{a}} = \bar{\epsilon} \gamma_{a} \lambda, \delta{\lambda} = -(1/2) \gamma_{a b} \epsilon f_{a b} }; \end{screen} The action is also written just as it is typed in~\TeX, \begin{screen}{1} S:= -(1/4) f_{a b} f_{a b} - (1/2) \bar{\lambda} \gamma_{a} \partial_{a}{\lambda}; \end{screen} Showing invariance starts by applying a variational derivative, \begin{screen}{1,5,6,7} @vary(%)( f_{a b} -> \partial_{a}{\delta{A_{b}}} - \partial_{b}{\delta{A_{a}}}, \lambda -> \delta{\lambda} ); @distribute!(%): @substitute!(%)( @(susy) ): @prodrule!(%): @distribute!(%): @unwrap!(%); \end{screen} After these steps, the result is (shown exactly as it appears in the \TeX{}macs~\cite{vdH:Gut} frontend) \begin{equation} S = \bar{\epsilon} \gamma_{a} \partial_{b} \lambda\, f_{ab} + \frac{1}{4} \overline{\gamma_{cb} \epsilon} \gamma_{a} \partial_a\lambda\, f_{cb} + \frac{1}{4} \bar{\lambda}\gamma_a \gamma_{cd} \epsilon \partial_a f_{cb}\,. \end{equation} Since the program knows about the properties of gamma matrices it can rewrite the Dirac bar, and then we do one further partial integration, \begin{screen}{1,2,3,4,5} @rewrite_diracbar!(%); @substitute!(%)( \partial_{c}{f_{a b}} -> \ppartial_{c}{f_{a b}} ): @pintegrate!(%){\ppartial}: @rename!(%){"\ppartial"}{"\partial"}: @prodrule!(%): @unwrap!(%); \end{screen} What remains is the gamma matrix algebra, sorting of spinors (which employs inheritance of the {\tt Spinor} and {\tt AntiCommuting} properties as already alluded to earlier) and a final canonicalisation of the index contractions, \begin{screen}{1,2,4,5} @join!(%){expand}: @distribute!(%): @eliminate_kr!(%): @prodsort!(%); @substitute!(%)( \partial_{a}{\bar{\lambda}} -> \bar{\partial_{a}{\lambda}} ); @spinorsort!(%): @rename_dummies!(%): @canonicalise!(%): @collect_terms!(%); \end{screen} The result is a Bianchi identity on the field strength, and thus invariance of the action. % \subsection{BRST transformations} % % \begin{equation} % \begin{aligned} % \delta A_\mu^a &= \epsilon D_\mu^{ab} c^b\,,\\[1ex] % \delta \psi &= i g\, \epsilon c^a t^a \psi\,,\\[1ex] % \delta c^a &= -\tfrac{1}{2} g \epsilon f^{abc} c^b c^c\,,\\[1ex] % \delta \hat{c}^a &= \epsilon B^a\,,\\[1ex] % \delta B^a &= 0\,. % \end{aligned} % \end{equation} % % \begin{screen}{0} % {a, b, c, d, e, f, g}::Indices. % f^{a b c}::AntiSymmetric. % C^{a}::SelfAntiCommuting. % R_{a b d e}::RiemannTensor. % % #f^{a b c} f^{c d e} ( A_\mu^b C^d C^e + A_\mu^d C^e C^b + A_\mu^e C^b C^d ); % R_{a b d e} ( A_\mu^b C^d C^e + A_\mu^d C^e C^b + A_\mu^e C^b C^d ); % @distribute!(%); % @canonicalise!(%); % @rename_dummies!(%); % @collect_terms!(%); % \end{screen} % %R_{a b d e} A_\mu^b C^d C^e; % \subsection{Perturbative gravity} % % % Perhaps the four-point vertex is nice to derive? % In perturbative Einstein gravity, we expand the metric around a fixed % background metric. This can get quite tedious at higher orders. Let us % first illustrate how such a perturbative expansion works at the lowest % order, for instance for~$R_{m n p q} R^{m n p q}$. This is obtained % with % \begin{screen}{0} % {l, m, n, s, t, u, v}::Indices(vector). % R_{l m n s}::RiemannTensor. % h_{m n}::Symmetric. % \diff{#}::PartialDerivative. % % 4 R_{l m n s} R_{l m n s}; % % @substitute!(%)( R_{l m n s} -> % @asym[ \diff{ h_{l s} }_{m n} - \diff{ h_{m s} }_{l n}]{_n, _s} ); % % @distribute!(%): % @canonicalise!(%): % @collect_terms!(%); % \end{screen} % The result is correct, but only because the inverse metrics which % contract the two Riemann tensors do % For next version: some way to write integrals and the like in % a natural notation. % % \begin{screen}{0} % {l, m, n, r, s, t, u, v, w}::Indices(vector, position=fixed). % R_{l m n s}::RiemannTensor. % R::RicciScalar. % R_{l m n s}::Depends(x). % R::Depends(x). % % \int_0^\infty R dx; % \end{screen} % some default input file which does collect_factors, collect_terms, % and so on as people expect. % ::PostDefaultRules( @@sumflatten!(%), @@prodsort!(%), @@collect_factors!(%), @@collect_terms!(%) ). % % ( eta_{n m} + k h_{n m} ) ( eta^{m p} + k h0^{m p} + k**2 h1^{m p} + k**3 h2^{m p}) = \delta_{n}^{p}; % @distribute!(%); % @substitute!(%)( eta_{n m} eta^{m p} -> \delta_{n}^{p} ); % # something to absorb eta, more elegantly than this. @eliminate_metric % # would do, since we already have @eliminate_kr. That could handle all % # such things, together with @eliminate_vielbein. % @substitute!(%)( eta_{n m} A?^{m p} -> A?_{n}^{p} ); % @substitute!(%)( eta^{m n} A?_{p m} -> A?_{p}^{n} ); % @factorise!(%){ h0_{n}^{p}, h_{n}^{p}, h1_{n}^{p}, h2_{n}^{p} }; % @substitute!(%)( A?? = B?? -> A?? - B?? = 0 ); % # Raise indices with eta. % # Some way to create substitution rules out of this. % # so that we end up with { h0_{n}^{p} -> h_{n}^{p}, h1_{n}^{p} -> % @coefficients(%){k}; % \begin{screen}{0} % {l, m, n, r, s, t, u, v, w}::Indices(vector, position=fixed). % R_{l m n s}::RiemannTensor. % R_{l m n s}::Depends(x). % h_{m n}::Symmetric. % g^{m n}::InverseMetric. % \diff{#}::PartialDerivative. % % 4 R_{l m n s} R^{l m n s}; % @rewrite_indices!(%){ R_{m n r s} }{ g^{m n} }; % % @substitute!(%)( R_{l m n s} -> % @asym[ \diff{ h_{l s} }_{m n} - \diff{ h_{m s} }_{l n}]{_n, _s} ); % % @distribute!(%): % @canonicalise!(%): % @collect_terms!(%); % \end{screen} % % % % \subsection{Super-QED in two-component language} % % This example follows the example in appendix C of~\cite{Lucic:1994nc}, % see also \cite{Ichinose:2006pc}. % % \begin{screen}{0} % {\alpha, \gamma, \delta, \beta }::Indices(spinor). % {\dot{\delta}, \dot{\gamma}, \dot{\alpha}, \dot{\beta}}::Indices(dottedspinor). % {\theta^{\alpha}, \psi^{\beta}}::SelfAntiCommuting. % {\theta^{\alpha}, \psi^{\beta}}::AntiCommuting. % \epsilon_{\alpha\beta}::AntiSymmetric. % {\theta^{\alpha}, \epsilon_{\alpha\beta}, \psi^{\alpha}}::SortOrder; % % \theta^{\gamma} \psi^{\beta} \epsilon_{\delta\gamma} \theta^{\delta}; % @prodsort!(%); % @canonicalise!(%); % % {\delta, \gamma, \alpha, \beta}::SelfAntiCommuting. % % {m,n,p}::Indices(flat). % % D( \theta^\delta \theta_\delta F )_\gamma; % @substitute!(%)( D( A?? )_{\gamma} -> \diff{ A?? }_{\gamma} % + i \bar{\theta}^{\dot{\alpha}} \diff{ A?? }_{m} \sigma^{m}_{\gamma \dot{\alpha}} ); % % @prodrule!(%); % @substitute!(%)( \diff{\theta^\alpha}_{\beta} = \delta^{\alpha}_{\beta} ); % @substitute!(%)( \diff{\theta^\alpha}_{m} = 0 ); % \end{screen} % % % \subsection{Eleven-dimensional supergravity} % % The eleven-dimensional supergravity action was first worked out % by~\dcite{crem1}. We would like to derive their form of the action by % constructing the most general supersymmetric action at two-derivative % level. % % The key new ingredient in this example is the use of the % \subscommand{@canonicalise} algorithm. % \vfill\eject % \subsection{Frequently asked questions} % % % This section discusses issues which rely on information from various % parts of the manual and are therefore less easy to find. % \begin{descerate} % \item[``How do \cdb's expression lists compare to notebooks?'']~\\ In % \cdb calculations are organised in a different way from standard % notebook-based computer algebra systems. The main feature is that % there is a more natural way of combining, into a group, all steps that % lead to the derivation of a certain result. In \cdb, this is done by % having each expression carry with it a history of manipulations that % led to it. This structure mimicks more closely what one is used to do % when one manipulates expressions by hand: one takes a given expression % as input, and applies successive algorithms to it (using externally % derived other expressions) until a final form has been arrived at. % % Compare the following two common constructions:\\[-2ex] % \begin{center} % \begin{minipage}{.4\textwidth} % \begin{screen}{0} % expr:= (x+y)^2; % @expand(expr); % @factor(expr); % \end{screen} % \end{minipage} % \begin{minipage}{.4\textwidth} % \begin{screen}{0} % expr:=(x+y)^2; % expr:=expand(expr); % expr:=factor(expr); % \end{screen} % \end{minipage} % \end{center} % \Cdb's form (on the left) more logically groups the manipulations of a % single expression. A different way to understand the organisation is % to think of each expression (together with its history) as a % mini-notebook. Within each such mini-notebook you do calculations just % like in Maple or Mathematica. The starting input of each mini-notebook % can be a newly entered expression or something copied from the result % of a previously evaluated mini-notebook. % \item[``How do I speed up large calculations?'']~\\ Turn off the % history. By default, a history is kept of all expressions, and the % {\tt @pop} command can be used to access previous forms of an % expression. When a calculation contains large expressions and many % algorithms acting on them, this history quickly consumes a lot of % memory. Use the setting {\tt ::KeepHistory(false)} to turn this off % altogether (see section~\ref{s:builtin} for details). Also, turn off % expression printing. By using the ``:'' delimiter instead of the ``;'' % one, output is suppressed (see section~\ref{s:input_format} for more % details). Not only does this make the output less messy, it also % speeds up the program. % % \item[``Why did you not implement this in Mathematica?'']~\\ % Many of the algorithms present in \cdb could have been implemented in % an existing symbolic manipulator such as Mathematica. However, there % is a certain point beyond which the Mathematica code would become more % and more ugly and harder to maintain. Take for instance the example of % the rule {\tt @eliminate\_kr}. This one could be implemented as % \begin{screen}{0} % eliminate_kr := { Delta[m_, m_] -> D } % \end{screen} % But \cdb does much more than this. It allows you to specify the % range of the indices (i.e.~the value of ``{\tt D}'' above) and it also % does not require you to use {\tt Delta} to represent the Kronecker % delta. So the appropriate rule is more like % \begin{screen}{0} % eliminate_kr := { D_?deltaset[m_, m_] -> ... } % \end{screen} % This becomes more and more complicated, and more importantly, diverges % more and more from an efficient and transparent rule-based system when % additional \cdb features are implemented. At some point one reaches a % stage where a conventional programming language like \Cpp shows its % advantages. % % \item[``Why not a separate data and meta language?'']~\\ (The data % language is the language used to write the objects we want to % manipulate; the expression~\verb|R_{m n p q}| is for instance part of % the data language. The meta language is the language which % describes what we want to do with these objects, % i.e.~\verb|ricci_cycle|). In many cases, the input files would look % nicer if we would have a separate data and meta language. Compare % \begin{center} % \begin{minipage}{.4\textwidth} % \begin{screen}{0} % expr:= A+B; % @substitute!(expr)( B -> C ); % \end{screen} % \end{minipage} % \begin{minipage}{.4\textwidth} % \begin{screen}{0} % expr:= A+B; % substitute B -> C into expr; % \end{screen} % \end{minipage} % \end{center} % However, the capability to pass any command or series of commands as % an argument to another command has great advantages (in fact, this is % one of the strengths of e.g.~LISP). Note that because \cdb does not do % automatic substitution of expressions, you can write both \verb|expr| % and \verb|@(expr)| and these mean something different. This is not quite % possible in other systems which have the same data and meta % language. Thinking in terms of pointers (and pointers to algorithm % nodes) is very useful in this respect. % \end{descerate} % % % % \vfill\eject \section{Graphical user interface} \subsection{General information} The graphical user interface is called {\tt xcadabra}. Context-sensitive help is available: if you put your cursor on a command or property name and press F1 or the help button, you will get a help screen (which is essentially the corresponding section in this manual). \subsection{Cell types} There are \emph{two} input cell types and \emph{two} output cell types. Normal input cells contain \cdb input. \TeX{} input cells contain comments which you can add to the notebook but which will not be sent to \cdb. Output cells can be either verbatim output, such as status messages, or \TeX{} output of expressions. Output cells are associated to input cells, so if you delete an input cell all the associated output cells will be removed too. In the current version there is no visual separation between cells. When you start a new blank notebook, your cursor is in the first input cell. After entering an expression there and pressing {\tt shift-enter}, this input cell will be evaluated and all output will be placed below it in the first output cell. In addition, a new input cell will be created below the output cell. The ``edit'' menu can be used to add input cells or delete them, and also shows keyboard shortcuts. \subsection{Editing, loading, saving, printing, exporting} % Use some screenshots to illustrate this. The file format used by the front-end is a \LaTeX{} compatible file. If necessary, it can be edited by hand using a text editor. As the file format which the front-end uses to save notebooks is a \LaTeX{} compatible file, it is simple to print a notebook: simply save it and run it through \LaTeX{} as usual. You will need two special-purpose packages, {\tt breqn} (which is separately packaged and also available from the AMS) and {\tt tableaux} (which is included with the \cdb distribution). Notebooks can be exported to a normal \cdb text input file. This results in a file which contains only the input cells of the notebook. Such a file can be fed into the command line version of \cdb by using \begin{screen}{1} cadabra --input [filename] \end{screen} The default extension for cadabra notebooks is {\tt .cnb}. \index{.cnb} For cadabra input files (for the command line version of \cdb) it is {\tt .cdb}.\index{.cdb} \subsection{Evaluating cells} In order to evaluate cells, press {\tt shift-enter} in an input cell. This will send the input to the kernel and display any results or informal messages below the input cell. \subsection{Algorithm and property auto-completion} The GUI has shell-like automatic completion of algorithm and property names. If you type only part of an algorithm or property, and subsequently press the \verb|TAB| key, the name will be completed to in maximally unambiguous way. For instance, by typing \verb|::Com| and hitting the \verb|TAB| key, the input will be completed to \verb|::Commuting|. By adding \verb|AsP| and hitting TAB again, this gets completed to \verb|::CommutingAsProduct|. \subsection{Cutting and pasting} You can select output cells and paste them back into input cells or into some other application. The program offers two formats for pasting, a \LaTeX{} one which is useful to paste into a paper, and a \cdb one which represents the way in which the expression can be pasted back into the program. In most cases, the format will be selected correctly automatically. Under Emacs, a middle-mouse paste will paste the \LaTeX{} version. You can paste the internal \cdb format by adding the following to your \verb|.emacs| file: \begin{screen}{0} (defun pastecdb () (interactive) (insert (x-get-selection-internal 'PRIMARY 'cadabra))) (global-set-key (kbd "C-x p") 'pastecdb) \end{screen} This will make the combination ``Ctrl-x p'' insert the current selection in \cdb internal format. For more advanced users: the list of formats can be inspected using \begin{screen}{1} (x-get-selection-internal 'PRIMARY 'TARGETS) [TIMESTAMP TARGETS MULTIPLE cadabra UTF8_STRING TEXT] \end{screen} If e.g.~an output cell with the content~\verb|1/2 A_{m}^{n}| is selected, the two different paste formats can be obtained by evaluating the following two LISP expressions in a scratch buffer, \begin{screen}{1} (x-get-selection-internal 'PRIMARY 'cadabra) #("1/2 A_{m}^{n};" 0 14 (foreign-selection STRING)) \end{screen} \begin{screen}{1} (x-get-selection-internal 'PRIMARY 'TEXT) #("1 := \frac{1}{2}\, A_{m}\,^{n};" 0 31 (foreign-selection COMPOUND_TEXT)) \end{screen} Note that the TEXT format contains markup such as spacing commands which make it more useful for papers. This is the default format when the middle mouse button is pressed. \subsection{The \TeX{}macs frontend} \label{s:texmacs} The program also comes with a \TeX{}macs frontend (which is now no longer actively maintained because the native graphical frontend is in many ways easier to use and more adapted to \cdb). If everything is installed correctly, the ``Insert $\rightarrow$ Session'' submenu of \TeX{}macs should contain an entry for \Cdb. A few sample \TeX{}macs files can be found in the {\tt texmacs} subdirectory of the source tarball. \Cdb sends its output more-or-less unchanged to the \TeX{}macs frontend. It is therefore useful to use tensor names which have a meaning in \TeX{}. For example, if you declare a derivative operator, you might be tempted to use \begin{screen}{1} \diff{#}::Derivative. \end{screen} (perhaps because you want to mimic Maple's notation). However, this will lead to ugly output since \texcommand{diff} is not a \TeX{} symbol and \TeX{}macs does not know what to do with it. A better choice would be \begin{screen}{1} \nabla{#}::Derivative. \end{screen} since \texcommand{nabla} actually prints as a nice symbol in \TeX{}macs. If you want to cut-and-paste formulas from a \TeX{} document into a \TeX{}macs notebook, you will encounter the problem that all backslashes get swallowed. To avoid this, choose the menu entry \begin{equation*} \text{Edit}\quad\rightarrow\quad \text{Paste from}\quad\rightarrow\quad \text{Verbatim} \end{equation*} which pastes text unmodified. You can make this the default for middle-button paste by choosing \begin{equation*} \text{Tools}\quad\rightarrow\quad \text{Selections}\quad\rightarrow\quad \text{Import}\quad\rightarrow\quad \text{Verbatim} \end{equation*} which will remain active during the current session. In order to make PDF output work, you have to have {\tt pfbtops}\index{pfbtops} installed (it is usually part of the {\tt groff} package). \vfill\eject \section{Reference guide} \subsection{Basics about the input format} \label{s:input_format} The input format of \cdb is closely related to the notation used by \TeX{} to denote tensorial expressions. That is, one can use not only bracketed notation to denote child objects, like in \begin{screen}{0} object[child,child] \end{screen} but also the usual sub- and superscript notation like \begin{screen}{0} object^{child child}_{child} \end{screen} One can use backslashes in the names of objects as well, just as in \TeX{}. All of the symbols that one enters this way are considered ``passive'', that is, they will go into the expression tree just like one has entered them. ``Active nodes'', on the other hand, are symbols pre-fixed with a ``@'' symbol. These are nodes which lead to an algorithm being applied to their children; they will thus not end up in the actual tree stored in memory, but instead get replaced with the output that their algorithm produces (if any). Finally, every non-empty expression that one enters will labelled by a number. Additionally, one can give an expression a label by entering it as ``\mbox{{\tt label-text:=~expression;}}''. One can use either the expression number or the label to refer to an expression. Names of objects can contain any printable character, except for brackets, sub- and super-script symbols and backslash characters (the latter can only occur at the beginning of a name). The sole exception to this rule is the names of active nodes: these names \emph{can} contain underscores to separate words. The program can also deal with ``accents'' added to symbol names, like \begin{screen}{0} \hat{A} \bar{B} \prime{Q} \end{screen} The precise way in which this works is explained in section~\ref{s:accents}. Input lines always have to be terminated with either a ``;'', a ``:'' or a ``.''. The first two of these delimiting symbols act in the same way as in Maple: the second form suppresses the output of the entered expression (see section~\ref{s:inputoutput} for additional information on how to redirect output to files). The last delimiter has the effect of evaluating the resulting expression, and immediately discarding it, also disabling printing. Long expressions can, because of these delimiters, be spread over many subsequent input lines. Any line starting with a ``\#'' sign is considered to be a comment (even when it appears within a multi-line expression). Comments are always ignored completely (they do not end up in the expression tree).\index{comments} All internal storage is in prefix notation, but a converter is applied to the input which transforms normal infix notation for products and sums to prefix notation. %Objects do not have to be declared before they can be used, although %some algorithmic modules may not work in this case. See %section~\ref{s:objprop} for more details. % TODO: - dX for differentials perhaps? % - dX.Psi for inner products? (already implemented) \subsection{Active nodes or ``commands''} \label{s:active_nodes} Active nodes are nodes which lead to immediate evaluation after the input has been entered; these could thus be called ``commands''. Commands always start with a ``@'' symbol, to distinguish them from normal, unevaluated input. Used in the standard ``notebook'' way, active nodes act on their first argument and get replaced with the result that they compute. This form uses square brackets to denote the argument on which to act: \begin{screen}{0} @command[expression]{arg1}{arg2}...{argn} \end{screen} If you want to re-use an existing expression as the argument, this can be cloned by using the ``@'' operator itself: \begin{screen}{0} @[equation number or label] \end{screen} or (for convenience, as a single exception to the square bracket rule) \begin{screen}{0} @(equation number or label) \end{screen} both evaluate to a copy of the expression to which they refer (one can use the ``\%'' character to denote the number of the last-used expression). Note that all of these forms create a \emph{new} expression. One is advised \emph{not} to refer to equation numbers using this command, as this makes expressions tied together in a rather fragile way. Algorithms can also be made to act on existing expressions such as to modify the expression history (i.e.~in the language of the previous section, to stay within a ``mini-notebook''). This is done by using round brackets instead of square ones: \begin{screen}{0} @command(expression number or label){arg1}{arg2}...{argn} \end{screen} Here it is no longer problematic to refer to equation numbers, as the result of this command will appear in the history list of the indicated expression (and is therefore not tied to the particular number of the expression). % Finally, there is a form which acts on % ``marked'' expressions, which will be discussed later. This form does % not have any reference to an object on which to act, since there is % only one ``marker''; it thus looks like % \begin{screen}{0} % @command{arg1}{arg2}...{argn} % \end{screen} % The way in which (parts of) expressions get marked depends on the % particular user interface; more information can be found in % section~\ref{s:marks}. All of these commands act on the top of the argument subtree. You can make them act subsequently on all nodes to which they apply by postfixing the name with an exclamation mark, as in \begin{screen}{0} @command![expression]{arg1}{arg2}...{argn} \end{screen} This will search the tree in pre-order style, applying the algorithm on every node to which the algorithm applies. If you want an algorithm to act until the expression no longer changes, use a double exclamation mark. Compare the single-exclamation mark version, \begin{screen}{1,2} A_{m} B_{m} A_{n} B_{n}; @substitute!(%)( A_{m} B_{n} -> Q); Q A_{n} B_{n}; \end{screen} with the double-exclamation mark one, \begin{screen}{1,2} A_{m} B_{m} A_{n} B_{n}; @substitute!!(%)( A_{m} B_{n} -> Q ); Q Q; \end{screen} Be careful with this functionality, as there is currently no safeguard in case the expression keeps changing forever. Instead of acting only at the top of the argument subtree, or acting on all nodes individually, it is also possible to act only a specific level of the expression. The notation for this is an exclamation mark with an extra number attached to it, which indicates the level (starting at 1 for the highest level), \begin{screen}{0} @command!level(expression number of label){arg1}{arg2}...{argn} \end{screen} Note that \verb|\sum| and \verb|\prod| nodes in the expression tree also count as a level. \subsection{Object properties and declaration} \label{s:objprop} Symbols in \cdb have no a-priori ``meaning''. If you write \verb|\Gamma|, the program will not know that it is supposed to be, for instance, a Clifford algebra generator. You will have to declare the properties of symbols, i.e.~you have to tell \cdb explicitly that if you write \verb|\Gamma|, you actually mean a Clifford algebra generator. This indirect way of attaching a meaning to a symbol has the advantage that you can use whatever notation you like; if you prefer to write \verb|\gamma|, or perhaps even \verb|\rho| if your paper uses that, then this is perfectly possible (object properties are a bit like ``attributes'' in {\tt Mathematica} or ``domains'' in {\tt Axiom} and {\tt MuPAD}). Properties are all written using capitals to separate words, as in {\tt AntiSymmetric}. This makes it easier to distinguish them from commands. Properties of objects are declared by using the ``::'' characters. This can be done ``at first use'', i.e.~by just adding the property to the object when it first appears in the input. As an example, one can write \begin{screen}{1} F_{m n p}::AntiSymmetric; \end{screen} This declares the object to be anti-symmetric in its indices and at the same time creates a new expression with this object. The property information is stored separately, so that further appearances of the ``\verb|F_{m n p}|'' object will automatically share this property. It is of course also possible to keep object property declarations separated (for instance at the top of an input file). This is done as follows: \begin{screen}{1,2} F_{m n p}::AntiSymmetric. F_{m n p}; \end{screen} A list of all properties is available in the graphical interface through the Help menu, and can also be obtained using the \subscommand{properties} command. Note that properties are attached to patterns. Therefore, you can have \begin{screen}{1,2} R::RicciScalar. R_{m n p q}::RiemannTensor. \end{screen} at the same time. The program will not warn you if you use incompatible properties, so if you make a declaration like above and then later on do \begin{screen}{1} R::Coordinate. \end{screen} this may lead to weird results. The fact that objects are attached to patterns also means that you can use something like wildcards. In the following declaration, \begin{screen}{1} { m#, n# }::Indices(vector). \end{screen} the entire infinite set of objects $m1, m2, m3, \ldots$ and $n1, n2, n3, \ldots$ are declared to be in the dummy index set ``vector''.\footnote{This way of declaring ranges of objects is similar to the \index{autodeclare}``autodeclare'' declaration method of FORM~\cite{Vermaseren:2000nd}.}\index{autodeclare}\index{\#} Range wildcards can also be used to match one or more objects of a specific type. In this case, they always start with a ``\#'' sign, followed by optional additional information to specify the type of the object and the number of them. The declaration \begin{screen}{0} {m,n,p,q,r,s}::Indices(vector). A_{ #{m, 1..3} }::AntiSymmetric. B_{ #{m} }::Symmetric. \end{screen} indicates that whenever the object \verb|A| appears with one to three indices of the vector type, it is antisymmetric. If the index type does not match, or if there are zero or more than three indices, the property does not apply. Similarly, \verb|B| is always symmetric when all of its indices are of the vector type.\index{\#}\index{range wildcards} Properties can be assigned to an entire list of symbols with one command, namely by attaching the property to the list. For example, \begin{screen}{1} {n, m, p, q}::Integer(1..d). \end{screen} This associates the property ``Integer'' to each and every symbol in the list. However, there is also a concept of ``list properties'', which are properties which are associated to the list as a whole. Examples of list properties are ``AntiCommuting'' or ``Indices''. See for a discussion of list properties section~\ref{s:list_properties}. Objects can have more than one property attached to them, and one should therefore not confuse properties with the ``type'' of the object. Consider for instance \begin{screen}{1,2,3} x::Coordinate. W_{m n p q}::WeylTensor. W_{m n p q}::Depends(x). \end{screen} This attaches two completely independent properties to the pattern $W_{m n p q}$. In the examples above, several properties had arguments (e.g. ``\verb|vector|'' or ``\verb|1..d|''). The general form of these arguments is a set of key-value pairs, as in \begin{screen}{1} T_{m n p q}::TableauSymmetry(shape={2,1}, indices={0,2,1}). \end{screen} In the simple cases discussed so far, the key and the equal sign was suppressed. This is allowed because one of the keys plays the role of the default key. Therefore, the following two are equivalent, \begin{screen}{1,2} { m, n }::Integer(range=0..d). { m, n }::Integer(0..d). \end{screen} See the detailed documentation of the individual properties for allowed keys and the one which is taken as the default. Finally, there is a concept of ``inherited properties''. Consider e.g.~a sum of spinors, declared as\index{properties!inheritance} \begin{screen}{1,2} {\psi1, \psi2, \psi3}::Spinor. \psi1 + \psi2 + \psi3; \end{screen} Here the sum has inherited the property ``Spinor'', even though it does not have normal or intrinsic property of this type. Properties can also inherit from each other, e.g. \begin{screen}{1,2,3} \Gamma_{#}::GammaMatrix. \Gamma_{p o i u y}; @indexsort!(%); \end{screen} The \subsprop{GammaMatrix} property inherits from \subsprop{AntiSymmetric} property, and therefore the {\tt $\backslash$Gamma} object is automatically anti-symmetric in its indices. A list of all properties known to \cdb can be obtained by using the \subscommand{proplist} command.\index{properties!list of all} % @exchange, which exchanges two terms in a product, should know % something about the commutator rule for two objects. But this is a % property of \prod? NO, that leads to putting many rules on prod, % exactly the kind of problem Mathematica is also facing. % Refer to DeWitt's compact index notation; indices can take values in % the integers or in any continuous set. \subsection{List properties and symbol groups} \label{s:list_properties} Some properties are not naturally associated to a single symbol or object, but have to do with collections of them. A simple example of such a property is \subsprop{AntiCommuting}. Although it sometimes makes sense to say that ``$\psi_m$ is anticommuting'' (meaning that $\psi_m \psi_n = - \psi_n \psi_m$), it happens just as often that you want to say ``$\psi$ and $\chi$ anticommute'' (meaning that $\psi\chi = - \chi\psi$). The latter property is clearly relating two different objects. Another example is dummy indices. While it may make sense to say that ``$m$ is a dummy index'', this does not allow the program to substitute $m$ with another index when a clash of dummy index names occurs (e.g.~upon substitution of one expression into another). More useful is to say that ``$m$, $n$, and $p$ are dummy indices of the same type'', so that the program can relabel a pair of $m$'s into a pair of $p$'s when necessary. In \cdb such properties are called ``list properties''. You can associate a list property to a list of symbols by simply writing, e.g. for the first example above, \begin{screen}{1} { \psi, \chi }::AntiCommuting. \end{screen} Note that, as described in section~\ref{s:objprop}, you can also attach normal properties to multiple symbols in one go using this notation. The program will figure out automatically whether you want to associate a normal property or a list property to the symbols in the list. Lists are ordered, although the ordering does not necessarily mean anything for all list properties (it is relevant for e.g.~\subsprop{SortOrder} but irrelevant for e.g.~\subsprop{AntiCommuting}). % When you `overwrite' a list property declaration, various things can % happen depending on the form of the list and the property used. Here % are some examples to illustrate this. In the first example, we % re-declare part of the objects in a previously declared set, % \begin{screen}{1,2,3} % {a,b,c,d,e}::Indices(vector). % {a,b,c}::Indices(spinor). % \end{screen} % This makes $a,b,c$ spinor indices and keeps $d,e$ as vector indices. A % similar example is % \begin{screen}{1,2,3} % {a,b,c}::Indices(vector). % {a,b,c,d,e,f}::Indices(spinor). % \end{screen} % in which all six indices become spinor indices. The next example adds % elements to a property list, % \begin{screen}{1,2} % {a,b,c}::Indices(vector). % {d,e}::Indices(vector). % \end{screen} % All indices are now members of a common list of vector % indices. Finally, there are cases in which properties are declared % with additional arguments, % \begin{screen}{1,2} % {a,b,c,d,e}::Indices(vector, position=free). % {a,b,c}::Indices(vector, position=fixed). % \end{screen} % In this case the first line declares a set of indices with name % `vector' with free index positions, while the second line % re-declares this set to have fixed index positions. The result is that % $a,b,c$ are now members of this set, while the property for $d,e$ is % removed altogether (as it is not possible to have more than one set of % indices with the `vector' label). \subsection{Indices, dummy indices and automatic index renaming} \label{s:automaticdummies} In \cdb, all objects which occur as subscripts or superscripts are considered to be ``indices''. The names of indices are understood to be irrelevant when they occur in a pair, and automatic relabelling will take place whenever necessary in order to avoid index clashes. \Cdb knows about the differences between free and dummy indices. It checks the input for consistency and displays a warning when the index structure does not make sense. Thus, the input \begin{screen}{1} A_{m n} + B_{m} = 0; \end{screen} results in an error message. The location of indices is, by default, not considered to be relevant. That is, you can write \begin{screen}{1,2} A_{m} + A^{m}; A_{m} B_{m}; \end{screen} as input and these are considered to be consistent expressions. If, however, the position of an index means something (like in general relativity, where index lowering and raising implies contraction with a metric), then you can declare index positions to be ``fixed''. This is done using \begin{screen}{1} {m, n, p}::Indices(position=fixed). \end{screen} When substituting an expression into another one, dummy indices will automatically be relabelled when necessary. To see this in action, consider the following example: \begin{screen}{1,2,5} {p,q}::Indices(vector). F_{m n} F^{m n}; F_{m n} F^{m n} G_{m n} @(1); G_{m n} F_{p q} F^{p q} \end{screen} The $m$ and $n$ indices have automatically been converted to $p$ and $q$ in order to avoid a conflict with the free indices on the $G_{m n}$ object. Refer to section~\ref{s:dummies} for commands that deal with dummy indices. %\bfcomment{KP}{Explain the canonicalisation algorithm and compare with %other approaches in the literature} \begin{table}[t] \begin{center} \begin{tabular}{rlll} argument & whitespace & dummy & example \\[1ex] \verb|{}| & product & & \verb|\frac{a b}{c} = \frac{a * b}{c}|\\ \verb|()| & product & & \verb|sin(a b) = sin(a * b)|\\ \verb|_{}| & separator & yes & \verb|M_{a b} = M_{a}_{b}|\\ \verb|^{}| & separator & yes & \verb|M^{a b} = M^{a}^{b}|\\ \verb|_()| & separator & & \verb|M_(a b) = M_(a)_(b)|\\ \verb|^()| & separator & & \verb|M^(a b) = M^(a)^(b)|\\ \verb|[]| & product & & \verb|[a b, c] = [a * b, c]| \end{tabular} \caption{The implicit meaning of objects and whitespace inside the various types of brackets.} \label{t:argtypes} \end{center} \end{table} \subsection{Exponents, indices and labels} Exponents, indices and labels are traditionally all placed using super- or subscript notation, making these slightly ambiguous for a computer algebra system. Since this situation can become quite complex (how do you represent the third power of the first element of a vector?) \cdb requires all powers to be entered with a double-star ``$**$'' notation:\footnote{Solutions involving the declaration of which indices are exponents and which are indices have been considered, but rejected in favour of the explicit ``$**$'' notation. Cases like ``the square of the second component of a vector'' quickly become ambiguous even with rather complicated property declarations, while the ``$**$'' notation remains transparent.} \begin{screen}{1,2} a**2; a**(2 + 3b); \end{screen} In addition, all sub- or superscripts with \emph{curly} braces indicate indices, to which the summation convention applies. In particular, there are not allowed to be more than two identical indices in a single product. The summation convention does not apply to arguments with any other bracket types. In particular, sub- or superscripts with \emph{square} or \emph{pointy} brackets have (as of yet) no fixed meaning. \subsection{Spacing and brackets} \Cdb is reasonably flexible as far as spacing and brackets are concerned, but the fact that objects do not have to be declared before they can be used means that spaces have to be introduced in some cases to avoid ambiguity. As a general rule, all terms in a product have to be separated by at least one whitespace character. Thus, \begin{quote} \begin{tabular}{ll} {\tt A(B+C)} & incorrect, (interpreted as {\tt A} with argument {\tt B+C}), \\[1ex] {\tt AB} & incorrect, (interpreted as one object, not two) \\[1ex] {\tt A (B+C)} & correct, \\[1ex] {\tt A*(B+C)} & correct. \end{tabular} \end{quote} If a whitespace character is absent, all brackets are interpreted as enclosing \emph{argument} groups. Products of variables (e.g.~$AB$) have to be separated by a space, otherwise the input will be read as the name of a single variable. However, spaces will automatically be inserted after numbers, between a closing bracket and a name or number, and between two names if the second name starts with a backslash. The following expressions are therefore interpreted as one would expect: \begin{quote} \begin{tabular}{ll} {\tt 3A} & interpreted as {\tt 3*A}\\[1ex] {\tt (A+B)C} & interpreted as {\tt (A+B)*C}\\[1ex] {\tt (A+B)3} & interpreted as {\tt (A+B)*3}\\[1ex] {\tt A$\backslash$Gamma}& interpreted as {\tt A*$\Gamma$}\\[1ex] \end{tabular} \end{quote} This conversion is done by the preprocessor. Finally, note that brackets in the input \emph{must} be balanced (a decision made to simplify the parser; it means that \cdb uses a different way to indicate groups of symmetric or anti-symmetric indices than one often encounters in the literature; see section~\ref{s:tensor}). \subsection{Implicit versus explicit indices} When writing expressions which involves vectors, spinors and matrices, one often employs an implicit notation in which some or all of the indices are suppressed. Examples are \begin{equation} a = M b\,,\qquad \bar{\psi}\gamma^{m}\chi\,, \end{equation} where~$a$ and~$b$ are vectors, $\psi$ and~$\chi$ are spinors and~$M$ and~$\gamma^{m}$ are matrices. Clearly, the computer cannot know this without some further information. In \cdb objects can carry implicit indices, through the \subsprop{ImplicitIndex} property. There are derived forms of this, e.g.~\subsprop{Matrix} and~\subsprop{Spinor}, \begin{screen}{1,2,3,4} {a,b}::ImplicitIndex; M::Matrix. a = M b; @prodsort!(%); @prodsort: not applicable. \end{screen} If you had not made the property assignment in the first two lines, the \subscommand{prodsort} would have incorrectly swapped the matrix and vector, leading to a meaningless expression. If you have more than one set of implicit indices, you can label them just like you can label explicit indices, \begin{screen}{1,2,3,4,5} {a,b}::ImplicitIndex(type1); {c,d}::ImplicitIndex(type2); M::Matrix(type1). a = M d c b; @prodsort!(%); a = M b d c; \end{screen} % It is also possible to declare that an object commutes with another % one even though they both carry implicit indices (e.g.~to indicate % that two matrices are commuting). % \subsection{Index brackets} Indices can be associated to tensors, as in~$T_{\mu\nu}$, but it often also happens that we want to associate indices to a sum or product of tensors, without writing all indices out explicitly. Examples are \begin{equation} (A + B + C)_{\alpha\beta}\,,\quad\text{or}\quad (\psi \Gamma_{m n} \Gamma_{p})_{\beta}\,. \end{equation} Here the objects $A$, $B$, $C$ and~$\Gamma$ are matrices, while~$\psi$ is a vector. Their explicit components are labelled with~$\alpha$ and~$\beta$ indices, but the notation above keeps most of these vector indices implicit. \Cdb can deal with such expressions through a construction which is called the ``indexbracket''. It is possible to convert from one form to the other by using the \subscommand{combine} and \subscommand{expand} algorithms. Combining terms goes like this, \begin{screen}{1,2} (\Gamma_r)_{\alpha\beta} (\Gamma_{s t u})_{\beta\gamma}: @combine!(%); (\Gamma_r \Gamma_{s t u})_{\alpha\gamma}; \end{screen} or as in \begin{screen}{1,2} (\Gamma_r)_{\alpha\beta} Q_\beta: @combine!(%); (\Gamma_r Q)_{\alpha}; \end{screen} If the index bracket has only one index, either the first or the last argument should be a matrix, but not both: \begin{screen}{1,2,4} A::Matrix. {m,n,p}::Indices(vector). (A B)_{m}; @expand(%); A_{m n} B_{n}; \end{screen} If the index bracket has two indices, all arguments should be matrices, \begin{screen}{1,2,3} {A,B}::Matrix. {m,n,p}::Indices(vector). (A B)_{m n}; @expand(%); A_{m p} B_{p n}; \end{screen} If there are more arguments inside the bracket, these of course all need to be matrices (and are assumed to be so by default). \subsection{Derivatives and implicit dependence on coordinates} \label{s:derivatives} There is no fixed notation for derivatives; as with all other objects you have to declare derivatives by associating a property to them, in this case the \subsprop{Derivative} property. \begin{screen}{1} \nabla{#}::Derivative. \end{screen} Derivative objects can be used in various ways. You can just write the derivative symbol, as in \begin{screen}{1} \nabla{ A_{\mu} }; \end{screen} (a notation used e.g.~in the tutorial example in section~\ref{s:tut_worldsheet}). Or you can write the coordinate with respect to which the derivative is taken, \begin{screen}{1,2,3} s::Coordinate. A_{\mu}::Depends(s). \nabla_{s}{ A_{\mu} }; \end{screen} Finally, you can use an index as the subscript argument, as in \begin{screen}{1,2} { \mu, \nu }::Indices(vector). \nabla_{\nu}{ A_{\mu} }; \end{screen} (in which case the first line is, for the purpose of using the derivative operator, actually unnecessary). The main point of associating the \subsprop{Derivative} property to an object is to make the object obey the Leibnitz or product rule, as illustrated by the following example, \begin{screen}{1,2,3} \nabla{#}::Derivative. \nabla{ A_{\mu} * B_{\nu} }; @prodrule!(%); \nabla{A_{\mu}} B_{\nu} + A_{\mu} \nabla{B_{\nu}}; \end{screen} This behaviour is a consequence of the fact that \subsprop{Derivative} derives from \subsprop{Distributable}. Note that the \subsprop{Derivative} property does not automatically give you commuting derivatives, so that you can e.g.~use it to write covariant derivatives. More specific derivative types exist too. An example are partial derivatives, declared using the \subsprop{PartialDerivative} property. Partial derivatives are commuting and therefore automatically symmetric in their indices, \begin{screen}{1,2,3,5,6} \partial{#}::PartialDerivative. {a,b,m,n}::Indices(vector). C_{m n}::Symmetric. T^{b a} \partial_{a b}( C_{m n} D_{n m} ); @canonicalise!(%); T^{a b} \partial_{a b}( C_{m n} D_{m n} ); \end{screen} \subsection{Accents} \label{s:accents} It often occurs that you want to put a hat or tilde or some other accent on top of a symbol, as a means to indicate a slightly different object. In most of these cases, the properties of the normal symbol and the accented symbol are identical. Such accents are declared using the \subsprop{Accent} property, as in \begin{screen}{0} \hat{#}::Accent. \end{screen} This automatically makes all symbols with hats inherit the properties of the unhatted symbols, \begin{screen}{1,2,3,4,5} \hat{#}::Accent. {\psi, \chi}::AntiCommuting. {\psi, \chi}::SortOrder. \hat{\chi} \psi: @prodsort!(%); (-1) \psi \hat{\chi}; \end{screen} If you want to put an accent on an object with indices, wrap the accent around the entire object, do not leave the indices outside. Note that it is also possible to mark objects by attaching sub- or superscripted symbols to them, as in e.g.~$A^\dagger$. This can be done by declaring these symbols explicitly using the \subsprop{Symbol} property, \begin{screen}{1} \dagger::Symbol. \end{screen} If you do not do this, \texcommand{dagger} will be seen as an index and an error will be reported if it appears more than twice. \subsection{Symbol ordering and commutation properties} \label{s:symbol_ordering} A conventional way to sort factors in a product is to use lexographical ordering. However, this is almost never what one wants when transcribing a physics problem to the computer. Therefore, \cdb allows you to specify the sort order of symbols yourself. This is done by associating the \subsprop{SortOrder} list property to a list of symbols, as in \begin{screen}{1,2,3} {X,G,Y,A,B}::SortOrder. A*B*G*X*A*X: @prodsort(%); X*X*G*A*A*B; \end{screen} More complicated objects with indices are of course also allowed, such as in \begin{screen}{1,2,3} { W_{m n}, W_{m} }::SortOrder. W_{m n} W_{p} W_{q r} W_{s} W_{t}: @prodsort(%); W_{m n} * W_{q r} * W_{p} * W_{s} * W_{t}; \end{screen} For the time being, it is not allowed to have more than one such set contain the same symbol. Thus, \begin{screen}{1,2} {X,G}::SortOrder. {X,A,B}::SortOrder. \end{screen} is not allowed (and will, in fact, take $X$ out of the first list). %> A*B*G*X: %@prodsort(%); %X*A*B*G; %Beware that the program does not prevent you from constructing %mutually contradictory sort orders: when a product sort is performed %and two factors have to be compared, the program will simply look in %the lists until it finds one particular list which contains the two %factors. Apart from the preferred sort order, there are more properties which influence the way in which products can be sorted. In particular, sort order is influenced by whether symbols commute or anti-commute with each other. Physicists in general use a very implicit notation as far as commutativity of objects in a product is concerned. Consider for instance a situation in which we deal with two operators $\hat M$ and $\hat N$, as well as some constants $q$ and $p$. These two expressions are equivalent: \begin{equation} 2q\, \hat M p \hat N \quad\text{and}\quad 2pq\, \hat M \hat N \,. \end{equation} But this is not obvious from the notation that has been used to indicate the product. In fact, the product symbol is usually left out completely. In many other computer algebra systems, you have to introduce special types of ``non-commuting'' products (e.g.~the \verb|&*| operator in Maple or the \verb|**| operator in Mathematica). This can be rather cumbersome, for a variety of reasons. The main reason, however, is that it does not match with what you do on paper. On paper, you never write special product symbols for objects which do not commute. You just string them together, and know from the properties of the symbols whether objects can be moved through each other or not. In order to make these sort of things possible in \cdb, it is necessary to declare ``sets'' of objects which mutually do not commute (i.e.~for which the order inside a product cannot be changed without consequences) but which commute with objects of other sets. Many computer algebra systems only use one such set: objects are either ``commuting'' or ``non-commuting''. This is often too restrictive. For instance, when $\Psi$ is a fermion and $\Gamma$ denotes a Clifford algebra element, a system with only one set of non-commuting objects is unable to see that \begin{equation} \bar\Psi_a (\Gamma_n\Gamma_m)_{ab} \Psi_b \quad\text{and}\quad \bar\Psi_a \Psi_b (\Gamma_n\Gamma_m)_{ab} \end{equation} are equivalent. In \cdb, one would simply put $\Psi_{a}$ and $\Gamma_{m}$ in two different sets, mutually commuting, but non-commuting among themselves. To be precise, the example above is reproduced by \begin{screen}{1,2,3,4,5} \bar{#}::Accent. \Psi_{a}::SelfNonCommuting. \Gamma_{#}::GammaMatrix. \bar{\Psi_a} (\Gamma_n \Gamma_m)_{ab} \Psi_b: @prodsort(%); \bar{\Psi_a} \Psi_b (\Gamma_n \Gamma_m)_{ab}; \end{screen} (see section~\ref{s:accents} for an explanation of the \subsprop{Accent} property). Commutation properties always refer to components. If you associate an \subsprop{ImplicitIndex} property to an object, then it will never commute with itself or with any other such object. You can see this in the example above, as the \subscommand{prodsort} command kept the order of the two gamma matrices unchanged. %\subsection{Component values and calculations} %\label{s:component_values} % %(This section is preliminary and experimental.) % gammacomponents: { \Gamma^{1}_{a b} = {{1,2,3},{1,2,4},..}, % \Gamma^{2}_{a b} = {{....} } % % \bar{\psi} \Gamma^\mu \psi V_{\mu} % @expand_index_bracket % @write_out!(%){ @(gammacomponents) }{ \mu }; % If you write out R_{m n p q} R_{m n p q} in components this leads % to d^4 terms. How can we reduce this so we do not double count? % The best way to minimise the number of terms is to assume that % we are, most of the time, contracting mostly-empty tensors. % (if you do not make that assumption then the computation will be % horrible anyway). % % R_{m n p q} T_{m n p q} % {1,3,2,5}=exp1 {2,4,3,5}=exp2 % {2,4,3,5}=exp3 {6,4,3,2}=exp3 % ... % % determine the number of non-zero components for % each tensor, taking into account Young projection. % Use this to sort the loop order below (use tensor % with lowest number of components in outer loop). % for(all non-zero components in tensor 1) % for(all non-zero components in tensor 2) % ... % if(the index values match) % multiply and store in sum. % % How do we instruct the program to compute components of % composite tensors? % % \Gamma_{m n}^{p} = 1/2 g^{p q} (\partial_{n}{g_{m q}} + % \partial_{m}{g_{n q}} - % \partial_{q}{g_{m n}} ); % % Here we need to associate coordinates to indices. % % {t,r,phi,theta}::Coordinate(polar). % {m,n,p,q,r}::Indices(vector, basis=polar). % g_{m n}::Metric(polar). % % R_{m n p}^{q} = \partial_{m}{\Gamma \subsection{Anti-commuting objects and derivatives} We have discussed anti-commuting objects to some extend in the previous section, but things become somewhat more hairy in combination with derivatives. Hence the current section, in which we will look in more detail at how to write properties which take care of anti-commuting derivatives (as they occur in e.g.~superspace field theories). We will use the \subscommand{prodrule} command to show how the various property assignments work. There are various ways in which you may want to write derivatives which are anti-commuting. One way is to use explicit indices, and declare them to be anti-commuting, as in \begin{screen}{1,2,3,4} {\alpha,\beta,\gamma}::Indices(spinor). {\alpha,\beta,\gamma}::AntiCommuting. D{#}::Derivative. D_{\alpha}{\theta^\beta \theta^\gamma}; D_{\alpha}{\theta^{\beta}} \theta^{\gamma} - \theta^{\beta} D_{\alpha}{\theta^{\gamma}}; \end{screen} Note the appearance of the minus sign for the second term. Writing things in this way is the most straightforward way to handle anti-commuting derivatives, and only requires the assignment of the \subsprop{AntiCommuting} property to the indices (second line above). However, one often deals with implicit indices when tackling problems involving anti-commuting variables. Here is an example to illustrate what is meant by this: \begin{screen}{1,2,3} test 19d does not do the right thing: it does not pick up a minus sign at the first step. \end{screen} \subsection{Input and output redirection} \label{s:inputoutput} By default, all generated output is displayed on the screen. As mentioned in section~\ref{s:input_format}, the delimiter of a line determines whether output is suppressed or not. It is, however, also possible to write output to a file, by appending a file name to the line delimiter, as in \begin{screen}{1} a^2+b^2 = c^2; "output_file" \end{screen} (note that there is no semi-colon following the file name). This shows the filename ``output\_file'' on the display, and writes to this file the expression \begin{screen}{0} 1:= a^{2}+b^{2}=c^{2} \end{screen} This is exactly as it would have appeared on the display. If you need a different kind of output, use the algorithms provided in the {\tt output} module (see section~\ref{s:output}). It is also possible to read input from files instead of from the terminal: \begin{screen}{1} < "input_file" \end{screen} reads from the file ``input\_file'' until the end or until a line \verb|@end;| is found, whichever comes first. Input redirect can be nested. In case an error occurs, reading from the file is also aborted and input is taken from the terminal again. \subsection{Default rules} By default, \cdb does very few things ``by itself'' with your expressions. This goes as far as not collecting equal terms, so that you can write \begin{screen}{1} A + A; \end{screen} and have this stored as a sum of two terms. However, you can add an arbitrary number of default commands, which are run just after you have entered an expression on the command line (\subsprop{PreDefaultRules}) or just before the output is returned to you (\subsprop{PostDefaultRules}). So if you want terms to be collected automatically, just enter \begin{screen}{1} ::PostDefaultRules( @@collect_terms!(%) ). \end{screen} Note the double ``@@'' symbol, which prevents immediate execution of the command. This post default rule will collect equal terms before they ever make it to internal storage. Many more complicated things can be achieved with this feature. You can, for instance, also use complicated substitution commands as arguments to \subsprop{PreDefaultRules} or \subsprop{PostDefaultRules}. An example is \begin{screen}{1,2,4} {m,n,p,q}::Indices(vector). ::PreDefaultRules( @@substitute!(%)( A_{m n} -> B_{m q} B_{q n} ). A_{m n} A_{n m}; \end{screen} which immediately returns \begin{screen}{0} B_{m q} B_{q n} B_{n p} B_{p m}; \end{screen} As usual dummy indices have been relabelled appropriately. \subsection{Patterns, conditionals and regular expressions} Patterns in \cdb are quite a bit different from those in other computer algebra systems, because they are more tuned towards the pattern matching of objects common in tensorial expressions, rather than generic tree structures. Name patterns are constructed by writing a single question mark behind the name, as in \begin{screen}{1} @substitute!(%)( A? + B? -> 0 ); \end{screen} which matches all sums with two terms, each of which is a single symbol without indices or arguments. If you want to match instead any object, with or without indices or arguments, use the double question mark instead. To see the difference more explicitly, compare the two substitute commands in the following example:\index{?}\index{??} \begin{screen}{1,2,4} A_{m n} + B_{m n}: @substitute!(%)( A? + B? -> 0 ); A_{m n} + B_{m n}; @substitute!(%)( A?? + B?? -> 0 ); 0; \end{screen} Note that it does not make sense to add arguments or indices to object patterns; a construction of the type ``\verb|A??_{\mu}(x)|'' is meaningless and will be flagged as an error. There is a special handling of objects which are dummy objects in the classification of section~\ref{s:automaticdummies} (see table~\ref{t:argtypes}). Objects of this type do not need the question mark, as their explicit name is never relevant. You can therefore write \begin{screen}{1} @substitute!(%)( A_{m n} -> 0 ); \end{screen} to set all occurrances of the tensor~$A$ with two subscript indices to zero, regardless of the names of the indices (i.e.~this command sets $A_{p q}$ to zero). When replacing object wildcards with something else that involves these objects, use the question mark notation also on the right-hand side of the rule. For instance, \begin{screen}{1} @substitute!(%)( A? + B? -> A? A? ); \end{screen} replaces all sums with two elements by the square of the first element. The following example shows the difference between the presence or absence of question marks on the right-hand side: \begin{screen}{1,2,4,5} C + D: @substitute!(%)( A? + B? -> A? A? ); C * C; @pop(%); @substitute!(%)( A? + B? -> A A ); A * A; \end{screen} Note that you can also use patterns to remove or add indices or arguments, as in \begin{screen}{1,2,3,5} {\mu,\nu,\rho}::Indices(vector). A_{\mu} B_{\nu} C_{\nu} D_{\mu}; @substitute!!(%)( A?_{\rho} B?_{\rho} -> \dot(A?)(B?) ); A.D B.C; @substitute!!(%)( \dot(A?)(B?) -> A?_{\mu} B?_{\mu} ); \end{screen} In many algorithms, patterns can be supplemented by so-called conditionals. These are constraints on the objects that appear in the pattern. For instance, the substitution command\index{conditionals} \begin{screen}{1} @substitute!(%)( A_{m n} B_{p q} | _{n}!=_{p} -> 0 ); \end{screen} applies the substitution rule only if the second index of $A$ and the first index of $B$ do not match. Note that the conditional follows directly after the pattern, not after the full substitution rule. A way to think about this is that the conditional is part of the pattern, not of the rule. The reason why the conditional follows the full pattern, and not directly the symbol to which it relates, is clear from the example above: the conditional is a ``global'' constraint on the pattern, not a local one on a single index. These conditions can be used to match names of objects using regular\index{regular expressions} expressions. Consider the following example: \begin{screen}{1,2} A + B3 + C7: @substitute!(%)( A + M? + N? | { \regex{M?}{"B[0-9]*"}, \regex{N?}{"[A-Z]7"} } -> sin(M? N?)/N? ); sin(B3 C7)/C7; \end{screen} It is also possible to select objects based on whether or not they are associated with a particular property, e.g.\footnote{More compact notations may look tempting, but were abandoned in favour of the constraint-based notation, the reason being that more compact notations tend to become hard to read when the constraint is more complicated.} \begin{screen}{1,2,3} A::SelfAntiCommuting. A A + B B; @substitute!(%)( Q?? Q?? | \hasprop{Q??}{SelfAntiCommuting} -> 0 ); B B; \end{screen} Combinations of different types of conditionals are of course also possible. This type of constraint can be used to construct replacement rules which act on objects of a certain type without knowing what their name is. The following example illustrates this. \begin{screen}{1,2,3} \sigma_{a?}::SigmaMatrix. \sigma_{1}\sigma_{2} + \rho_{1} \rho_{2}; @substitute!(%)( S?_{1} S?_{2} | \hasprop{S?_{1}}{SigmaMatrix} -> I*S?_{3} ); I \sigma_{3} + \rho_{1} \rho_{2}; \end{screen} This could also have been written without specifying the numerical values of the indices explicitly, \begin{screen}{1,2,3} \sigma_{a?}::SigmaMatrix. \sigma_{1}\sigma_{2} + \rho_{1} \rho_{2}; @substitute!(%)( S?_{a?} S?_{b?} | \hasprop{S?_{a?}}{SigmaMatrix} -> I*\epsilon_{a? b? c} \sigma_{c} ); I \epsilon_{1 2 c} \sigma_{c} + \rho_{1} \rho_{2}; \end{screen} As a general rule, patterns on the right-hand side of a substitution rule get replaced even if their parent relation does not match the one on the left-hand side, \begin{screen}{1,2,3} q_{c d}; @substitute!(%)( q_{a b} -> a Q_{a b} ); c Q_{c d}; \end{screen} This follows the general logic of explicit wildcards, \begin{screen}{1,2,3} q_{c d}; @substitute!(%)( q_{a? b?} -> a? Q_{a? b?} ); c Q_{c d}; \end{screen} If this is not what you want, just rename the dummy index labels, \begin{screen}{1,2,3} q_{c d}; @substitute!(%)( q_{e f} -> a Q_{e f} ); a Q_{c d}; \end{screen} %Note that declarations and substitution both use patterns, but the %latter are a superset of the former. That is, declarations at present %only accept dummy index patterns and range wildcards. A construction like %\begin{screen}{0} %{ m? | \regex{m?}{"a[0-9]*"} }::Integer. INVALID %\end{screen} %is not yet allowed. % This makes the symbols $a0$, $a1$, $a2$ and so on integers. Here one % sees once more that the conditional is part of the full pattern. The % entire expression inside the curly brackets should be considered a % pattern. Note that the following expressions are all equivalent: % \begin{screen}{0} % { R?_{m? n? p? q?} | \regex{R?}{"R"} }::RiemannTensor. % { R?_{m n p q} | \regex{R?}{"R"} }::RiemannTensor. % R_{m? n? p? q?}::RiemannTensor. % R_{m n p q}::RiemannTensor. % \end{screen} % The versions without the question marks on the indices match % any index names by virtue of the rule in section~\ref{s:automaticdummies}. \subsection{Procedures} Although the present version of \cdb does not contain a full-fledged programming language, it does allow you to construct groups of commands which can be applied term-by-term on a large sum. This is sometimes useful if e.g.~the application of a command on a single term already leads to a large intermediate result. Procedures are defined by making use of the \cdbcommand{procedure}{} construction. Here is an example, which distributes all products and performs a substitution: \begin{screen}{1,2,3,4,5} @procedure{ExpandAndCollect}; @distribute!(%); @substitute!(%)( A C -> Q ); @collect_terms!(%); @procedure_end; \end{screen} A sample session which calls this procedure is \begin{screen}{1,2,3,4} (A+C)*(B+C+A) + C*(E+A); @call{ExpandAndCollect}; \end{screen} This produces some status output, followed by \begin{screen}{0} A B + 2 Q + A A + C B + C C + C E + Q; \end{screen} Note how the commands inside the procedure only act on each term in turn. The \subscommand{collect\_terms} command has only collected two \verb|Q| symbols which arose from the first term. Note also that all output of the commands inside the procedure has been suppressed, despite the appearance of the semi-colon line delimiter. \subsection{Reserved node names} \label{s:reserved_names} There is a small number of node names which is reserved to always mean the same thing, i.e.~for which the properties are not determined by the property system. These can be obtained using the `@reserved' command. Explicitly, they are % % If any of these change, they need to be changed in the output % routine of manipulator.cc as well. % \begin{quote} \texcommand{anticommutator}, \texcommand{arrow}, \texcommand{comma}, \texcommand{commutator}, \texcommand{conditional}, \texcommand{frac}, \texcommand{cdot}, \texcommand{equals}, \texcommand{expression}, \texcommand{factorial}, \texcommand{indexbracket}, \texcommand{infty}, \texcommand{label}, \texcommand{pow}, \texcommand{prod}, \texcommand{regex}, \texcommand{sequence}, \texcommand{sum}, \texcommand{unequals}. \end{quote} Moreover, \cdb uses a number of standard names for mathematical operators as reserved keywords, to wit \begin{quote} \texcommand{sin}, \texcommand{cos}, \texcommand{tan}, \texcommand{sinh}, \texcommand{cosh}, \texcommand{tanh}, \texcommand{arcsin}, \texcommand{arccos}, \texcommand{arctan}, \texcommand{sqrt} \end{quote} Some properties of these nodes are still obtained from the property system in order to make algorithms look more uniform, but the names of these reserved nodes can not be changed. \begin{reserved} \input{reserved/anticommutator.tex} \input{reserved/arrow.tex} \input{reserved/comma.tex} \input{reserved/commutator.tex} \input{reserved/conditional.tex} \input{reserved/frac.tex} \input{reserved/cdot.tex} \input{reserved/equals.tex} \input{reserved/expression.tex} \input{reserved/factorial.tex} \input{reserved/indexbracket.tex} \input{reserved/infty.tex} \input{reserved/label.tex} \input{reserved/pow.tex} \input{reserved/prod.tex} \input{reserved/regex.tex} \input{reserved/sequence.tex} \input{reserved/sum.tex} \input{reserved/unequals.tex} \end{reserved} \subsection{Startup and program options} There are a few startup options for the command line version of \cdb. If present, a startup file {\tt \verb|~/.cadabra|} \index{.cadabra}\index{startup file} will be read when the program is started (only when running cadabra in command-line mode). This file can contain any \cdb input. \begin{description} \item[{\tt -{}-{}bare}] Disable reading of the startup file \verb|~/.cadabra|. \item[{\tt -{}-{}silent}] Disable normal output (so that the only remaining output is through output redirection into files). \item[{\tt -{}-{}input [filename]}] Before switching to interactive mode, first read and process the indicated file. \item[{\tt -{}-{}prompt [string]}] Set the \cdb prompt to the given string. \item[{\tt -{}-{}silentfail}] Silently fail (i.e. do not complain) if an algorithm is activated which cannot be applied. \item[{\tt -{}-{}loginput}] Write the input into the debug file as well. \item[{\tt -{}-{}nowarnings}] Suppress displaying of any warnings which are not fatal errors. \item[{\tt -{}-{}texmacs}] Send output in TeXmacs format. \end{description} In order to have command-line editing functionality, the {\tt prompt} program is provided. So the two ways of starting \cdb are \begin{screen}{0} cadabra prompt cadabra \end{screen} the second of which gives cursor control and an editing history. There are various other settings of \cdb which can be influenced through environment variables; see section~\ref{s:environment_variables} for details. \subsection{Environment variables} \label{s:environment_variables} \index{environment variables}There are a few environment variables which may be set to influence the behaviour of cadabra: \begin{descerate} \item[CDB\_LOG] \index{CDB\_LOG} When set, debug logging will be enabled. %\item[CDB\_CHECK\_INPUT] \index{CDB\_CHECK\_INPUT} If set, check all % input lines for index consistency. \item[CDB\_ERRORS\_ARE\_FATAL] \index{CDB\_ERRORS\_ARE\_FATAL} If this variable is set, errors (inconsistency of the tree or attempted use of non-existing algorithm) will abort the program (the default action, when this variable is unset, is to ignore the offending input line). \item[CDB\_PARANOID] \index{CDB\_PARANOID} Perform extensive consistency checks on the internal data format after each algorithm has been applied (only useful for debugging). \item[CDB\_PRINTSTAR] \index{CDB\_PRINTSTAR} Determines whether or not multiplication star symbols are displayed. \item[CDB\_TIGHTSTAR] \index{CDB\_TIGHTSTAR} Make output of multiplication symbols more compact. \item[CDB\_TIGHTBRACKETS] \index{CDB\_TIGHTBRACKETS} Make output of bracketed expressions more compact. \item[CDB\_USE\_UTF8] \index{CDB\_USE\_UTF8} Use UTF8 line breaking characters in the output. \end{descerate} % \subsection{Future plans} % % Now that the program is beginning to reach a usable and stable state, % a number of directions for future work suggest themselves: % \begin{itemize} % \item A new parser; the current one was hand-written for many reasons, % and is messy and not entirely correct. Now that the input format has % stabilised it is time for a parser which is easier to debug, % e.g.~one based on {\tt lex} \& {\tt yacc}. % \item Inclusion of proper program flow including loops and % subroutines. % \end{itemize} % Any suggestions on these or other topics are welcome. %----------------------------------------------------------------- \vfill\eject \section{Algorithm modules} \label{s:modules} All algorithms are stored in modules separate from the core of the program. These are at present all distributed together with the main program, but will in the future be available separately as binary or source plugin modules that can be loaded on demand. Any expression that starts with a name beginning with an ``@'' symbol is interpreted as a command. Commands act on the currently selected objects in an expression or on the expression for which the label or number is given as the first argument. See section~\ref{s:active_nodes} for more details on how to apply algorithms to expressions. \begin{multicols}{2} \printnomenclature %\printglossary \end{multicols} \vfill\eject \subsection{Built-in core algorithms} \label{s:builtin} There is a very small number of properties and algorithms built into the core program. These have to do with global memory management and global output settings. \bigskip \begin{props} \input{properties/KeepHistory.tex} \input{properties/PreDefaultRules.tex} \input{properties/PostDefaultRules.tex} \end{props} \bigskip \begin{algs} \input{algorithms/pop.tex} \input{algorithms/amnesia.tex} \input{algorithms/algorithms.tex} \input{algorithms/properties.tex} \input{algorithms/timing.tex} \input{algorithms/output_format.tex} \input{algorithms/quit.tex} \input{algorithms/end.tex} \input{algorithms/reset.tex} \input{algorithms/xterm_title.tex} %\item[\cdbcommand{utf8\_output\{true|false\}}{}] Determines whether %the output should contain UTF8 encoded Unicode control characters for %line-breaking and object grouping. This output format is used by the %graphical front-end. \end{algs} \vfill\eject \subsection{Rationals, complex numbers and other numerics} \begin{props} %\item[\cdbprop{ImaginaryI}{}] Indicates that the object squares to % $-1$. %\item[\cdbprop{Real}{}] %\item[\cdbprop{Imaginary}{}] %\item[\cdbprop{Complex}{}] \input{properties/Integer.tex} \input{properties/NumericalFlat.tex} \end{props} \bigskip \begin{algs} %\item[\cdbcommand{eval\_factorial}{}] Evaluate the numerical value of %a factorial expression, e.g.~turn $5!$ into $120$.\kcomment{KP}{Not %yet implemented} \input{algorithms/numerical_flatten.tex} \end{algs} \vfill\eject \subsection{Sums and products} \label{m:algebra} This module handles expansion of sums and products as well as distributing products over sums and similar algorithms. It recognises \bigskip \begin{props} \input{properties/Matrix.tex} \input{properties/ImplicitIndex.tex} \input{properties/Diagonal.tex} \input{properties/SelfAntiCommuting.tex} \input{properties/SelfNonCommuting.tex} \input{properties/SelfCommuting.tex} \input{properties/Distributable.tex} \input{properties/AntiSymmetric.tex} \input{properties/Symmetric.tex} \input{properties/TableauSymmetry.tex} \input{properties/DAntiSymmetric.tex} \input{properties/Commuting.tex} \input{properties/NonCommuting.tex} \input{properties/AntiCommuting.tex} \input{properties/CommutingAsProduct.tex} \input{properties/CommutingAsSum.tex} \input{properties/Traceless.tex} \input{properties/KroneckerDelta.tex} \input{properties/EpsilonTensor.tex} \input{properties/SortOrder.tex} \input{properties/Derivative.tex} \input{properties/PartialDerivative.tex} \end{props} \begin{algs} \input{algorithms/prodflatten.tex} \input{algorithms/sumflatten.tex} \input{algorithms/remove_indexbracket.tex} \input{algorithms/expand_power.tex} %\input{algorithms/drop.tex} \input{algorithms/drop_weight.tex} \input{algorithms/keep_weight.tex} \input{algorithms/distribute.tex} \input{algorithms/prodrule.tex} \input{algorithms/sumsort.tex} \input{algorithms/prodsort.tex} \input{algorithms/collect_factors.tex} \input{algorithms/collect_terms.tex} \input{algorithms/factor_out.tex} \input{algorithms/factor_in.tex} \input{algorithms/canonicalise.tex} \input{algorithms/reduce.tex} \input{algorithms/young_project.tex} \input{algorithms/all_contractions.tex} \end{algs} \vfill\eject \subsection{Young tableaux} Young diagrams (with unlabelled boxes) and Young tableaux (with labelled boxes) can be manipulated directly, and \cdb contains routines to e.g.~compute tensor products or to put tableaux in standard form using all their symmetries. In order to avoid confusion about the meaning of ``diagram'' and ``tableau'', a Young tableau with labelled boxes is called a ``FilledTableau'' in \cdb, while a tableau without any labels in the boxes is a ``Tableau''. \bigskip \begin{props} \input{properties/Tableau.tex} \input{properties/FilledTableau.tex} \end{props} \begin{algs} \input{algorithms/tabdimension.tex} \input{algorithms/tabcanonicalise.tex} \input{algorithms/tabstandardform.tex} \input{algorithms/lr_tensor.tex} \input{algorithms/decompose.tex} \input{algorithms/decompose_product.tex} \end{algs} \vfill\eject \subsection{Lists and ranges} When using list algorithms, be aware of the fact that when they act on an argument, they actually replace the argument, not generate a new one. Therefore, to generate a new expression which contains the length of another expression, \begin{screen}{1,3} A+B+C+D; 1:= A+B+C+D; @length[@(1)]; 2:= 4; \end{screen} This is to be compared with \begin{screen}{1,3} A+B+C+D; 1:= A+B+C+D; @length(1); 1:= 4; \end{screen} in which case the first expression gets replaced by its length. \medskip \begin{algs} \input{algorithms/length.tex} \input{algorithms/take.tex} \input{algorithms/range.tex} \input{algorithms/inner.tex} \input{algorithms/list_sum.tex} \input{algorithms/listflatten.tex} \input{algorithms/permute.tex} \end{algs} \vfill\eject %\subsection{Differential geometry} % %\label{s:diff_geom} %\begin{props} %\item[\cdbprop{DifferentialForm}{}] %\end{props} %\bigskip %\begin{algs} %\end{algs} \subsection{Properties} \label{s:properties} \begin{props} \input{properties/PropertyInherit.tex} \input{properties/IndexInherit.tex} \end{props} %\begin{algs} %\item[\cdbcommand{extract\_properties}{}] An algorithm mainly useful %in internal routines: it extracts properties attached to a symbol and %adds them to the global property list. Gets called automatically on %input. %\end{algs} % \vfill\eject \subsection{Dummy indices} \label{s:dummies} Dummy indices are a subject by itself. There are various problems with most implementations of dummy indices in computer algebra software. In many cases, dummy indices are added as an afterthought, leading to situations were illegal expressions (e.g. with a more than twice repeated dummy index) can be entered. Even if this is flagged, most programs do not know about different index types (which leads to problems when there is more than one type of contraction, or a sum over only part of the index range). In \cdb, the system knows about dummy index \emph{sets}, and all algorithms can request new dummy indices very easily. This is handled through the {\tt dummies} module. \bigskip \begin{props} \input{properties/Indices.tex} \end{props} \begin{algs} \input{algorithms/rename_dummies.tex} \end{algs} \vfill\eject \subsection{Symmetrisation and anti-symmetrisation} % This is actually implemented in algebra.cc, the sym.cc is empty This module contains algorithms for the symmetrisation or anti-symmetrisation of expressions in their elements, and for the inverse procedure, whereby object trees are identified when they differ only by certain symmetrisations or anti-symmetrisations. %This module relies strongly on the {\tt combinatorics.hh} header file, %which contains algorithms that generate various combinations and %permutations of sets. %\url{http://dogma.net/markn/articles/Permutations/} \bigskip \begin{algs} \input{algorithms/sym.tex} \input{algorithms/asym.tex} \input{algorithms/canonicalorder.tex} \input{algorithms/impose_asym.tex} \input{algorithms/asymprop.tex} \end{algs} \vfill\eject \subsection{Field theory} \label{s:tensor} \bigskip \begin{props} \input{properties/SelfDual.tex} \input{properties/AntiSelfDual.tex} \input{properties/Depends.tex} \input{properties/DependsInherit.tex} \input{properties/Weight.tex} \input{properties/WeightInherit.tex} \input{properties/Symbol.tex} \input{properties/Coordinate.tex} \input{properties/Accent.tex} \input{properties/SatisfiesBianchi.tex} \end{props} \bigskip \begin{algs} \input{algorithms/unwrap.tex} \input{algorithms/eliminate_kr.tex} \input{algorithms/eliminateeps.tex} \input{algorithms/epsprod2gendelta.tex} \input{algorithms/dualise_tensor.tex} \input{algorithms/reduce_gendelta.tex} \input{algorithms/product_shorthand.tex} \input{algorithms/expand_product_shorthand.tex} \input{algorithms/pintegrate.tex} \input{algorithms/impose_bianchi.tex} \input{algorithms/einsteinify.tex} \input{algorithms/combine.tex} \input{algorithms/expand.tex} \end{algs} ~ \vfill\eject \subsection{Output routines} \label{s:output} The core of \cdb only knows how to output its internal tree format in infix notation, and by default displays the result of every input line in this way (labelled by the expression number and label, if any). For more complicated output, for instance to feed \cdb expressions to other programs, or to see the internal tree form, routines are available in the {\tt output} module. Note that these modules do not transform the tree or generate new expressions; they \emph{only} generate output. Related but \emph{different} functionality is present in the {\tt convert} module, which contains transformation algorithms which transform the internal tree to other conventions (e.g.~in order to convert a \cdb tree to a tree which can be understood by Maple or Mathematica). \bigskip \begin{props} \input{properties/LaTeXForm.tex} \end{props} \bigskip \begin{algs} \input{algorithms/depprint.tex} \input{algorithms/print.tex} \input{algorithms/number_of_terms.tex} \input{algorithms/proplist.tex} \input{algorithms/assert.tex} \end{algs} \bigskip\bigskip \noindent Furthermore, there are a few algorithms which are mainly useful for debugging purposes, as they display information about the internal representation of the expression tree. More information on the internal data structures can be found in section~\ref{s:internal_storage}. \bigskip \begin{algs} \input{algorithms/tree.tex} \input{algorithms/indexlist.tex} \end{algs} \vfill\eject % \subsection{Perturbative string theory ({\tt pertstring})} % % % This module contains useful routines for the computation of % perturbative string amplitudes, that is, it contains information about % Jacobi theta functions and assorted things. % \bigskip % \begin{algs} % \item[\cdbcommand{aticksen}{}] Work out a fermionic correlator according to % \dcite{Atick:1987rs}. These correlators contain SO(2) spinors % represented in the form of a complex fermion $\Psi$ and $\bar\Psi$, as % well as spin fields $S_+$ and $S_-$ \kcomment{KP}{Lacking % ``properties'', these currently have to be written as {\tt Psi}, {\tt % Psibar}, {\tt Splus} and {\tt Sminus}.}. Correlators of these are written as % {\tt \\corr\{...\}}, where the dots contain an arbitrary number of these % fermionic fields, together with their dependence on insertion points. % The algorithm converts these correlators to Jacobi theta function expressions, % (ignoring a normalisation constant) using the expression % \begin{equation} % \begin{aligned}[t] \Big\langle \prod_{i=1}^{N_1}& S^+(\tilde y_i) % \prod_{i=1}^{N_2} S^-(y_i) \prod_{i=1}^{N_3} \bar\Psi(\tilde z_i) % \prod_{i=1}^{N_4} \Psi(z_i)\Big\rangle_\nu \\[1ex] % {} & = K_\nu \frac{\displaystyle \prod_{i} templated over the type of the objects to be permuted. This class acts as a container holding both the original vector (in the {\tt storage} member), the permutation patterns (in the {\tt sublengths} vector, more on this later) as well as the resulting permuted vectors (accessible through {\tt operator[]}; the total number of combinations is given by {\tt size()}). \end{description} \subsection{Tree representation of expressions} \label{s:internal_storage} Expressions are internally stored in a tree container class, based on the {\tt tree.hh} library~\cite{kas_tree}. The present section describes the tree format in some more detail. Let us start with a couple of remarks on the motivation which has led to the current implementation. An important requirement for the storage format is that symbols should not have a fixed meaning, but rather be like variables in a computer program: they can be declared to represent objects of a certain type. Similarly, the user should be free to use arbitrary bracket types and sub- and superscript indicators (these should in addition be kept during the algebraic manipulations). The first issue is resolved with the property system, but the second one needs support directly in the storage tree. Secondly, storage should be such that a trivial (often occurring) extensions from one object to another should not lead to blowup. For instance, the difference between \verb|A_\mu| and \verb|A_{\mu \nu}| should preferably not introduce a new layer between the \verb|A| node and the \verb|\mu| node. This is achieved by adding the bracket type to the \emph{child} node rather than the parent (in the example above, the curly brackets are part of the \verb|\mu| and \verb|\nu| nodes). This applies also to e.g.~sums: in \verb|(A+B)| (which is converted by the preprocessor to \verb|\sum(A)(B)| ), the round brackets are part of the child nodes of the \verb|\+| node.\footnote{Subsequent child nodes with the same bracket type associated to them are taken to be part of the same group; the input {\tt A\_\{$\backslash$mu\}\_\{$\backslash$nu\}} will therefore be printed as {\tt A\_\{$\backslash$mu $\backslash$nu\}}. Similarly, there is no way to represent $(a)+(b)$ since the internal storage format automatically turns this into $(a+b)$.} Similarly, extending \verb|q| to \verb|3q| should not introduce new intermediate layers to group the two symbols together. This has been achieved by giving each node a multiplier field (this holds true even for products, i.e.~\verb|3(a+b)| is represented as a sum node with multiplier 3 (in addition, such numerical factors are always commuted to the front of the expression).\footnote{The multiplier field is a rational, and is intended to stay that way. It is not a good idea to make it complex, otherwise we will end up with octonionic multipliers at some stage. } %We need some pre-defined symbols %for $i$ and so on though, and rules to simplify products of %them. These rules can be kept explicit and user-switchable to be %automatic.} It should also be possible to make expressions arbitrarily deeply nested; one should be able to write \verb|a+b| as well as \verb|\sin(a+b)|. This is in contrast to programs such as {\tt Abra} and {\tt FORM} which store their input as sums of products of factors, i.e.~without further nesting. Finally, tt should be posssible to store the history of an expression, in order to implement unlimited undo. The data stored at each tree node is further explained in section~\ref{s:writing_new}, see in particular the excerpt from the {\tt storage.hh} file in figure~\ref{f:str_node}. The structure of the actual tree is illustrated in figure~\ref{f:example_history}. Each expression starts with a {\tt history} node. The label of the expression is given in a subnode {\tt label}. All remaining child nodes of the {\tt history} nodes represent the history of the expression. The most often encountered node here is the {\tt expression} node, which contains the actual expression. However, there are other nodes as well, for instance {\tt asymimplicit} which contains information about the symmetry structure of an expression (this feature is not yet enabled). \begin{figure}[t] \begin{equation*} \vcenter{\offinterlineskip \halign{&#\mystrut\hfil\cr \texcommand{history} \cr \T \texcommand{label}\cr \V \L apple \cr \T \texcommand{expression} \cr \V \L \texcommand{prod} \cr \V \N \T a \cr \V \N \L \texcommand{sum} \cr \V \N \N \T b \cr \V \N \N \L c \cr \L \texcommand{expression} \cr \N \L \texcommand{sum} \cr \N \N \T \texcommand{prod} \cr \N \N \V \T a \cr \N \N \V \L b \cr \N \N \L \texcommand{prod} \cr \N \N \N \T a \cr \N \N \N \L c \cr }} \end{equation*} \caption{Example history tree for a single expression. Here, the program started with the user entering the expression $a (b+c)$. This expression was then manipulated by applying the \subscommand{distribute} algorithm. The nodes at the top of the expression tree are all of the {\tt history} type. \label{f:example_history}} \end{figure} % \T \texcommand{action}\cr % \V \T \subscommand{exchange}\cr % \V \N \T a\cr % \V \N \L b\cr % \quad\quad\longleftrightarrow\quad\quad % \vcenter{ % \offinterlineskip % \halign{&#\mystrut\hfil\cr % (1) $a+b$ \cr % \T exchange \cr % \V \L \,$b+a$\cr % \V \N \,rmult $d$\cr % \V \N \L \,$(b+a) d$ $\bullet$\cr % \L lmult $c$\cr % \N \L \,$c(a+b)$ \cr}} \subsection{Nested sums, products and pure numbers} Nested sum and product nodes require some explanation, as the way in which \cdb handles and stores these determines how brackets can appear in sums and products. As a general rule, sums within sums which are such that all child nodes have the same, non-visible bracket are not allowed, and automatically converted to a single sum. In other words \begin{screen}{0} (\sum{a}{b}+\sum{c}{d}) \end{screen} is not allowed, since it would print as \verb|(a+b+c+d)| which is indistinguishable from \begin{screen}{0} (\sum{a}{b}{c}{d}) . \end{screen} The first expression is therefore internally always converted to the second one before it is stored. A similar situation occurs with products, where \begin{screen}{0} \prod{a}{\prod{b}{c}} \end{screen} is not allowed and ``flattened'' to the simpler \begin{screen}{0} \prod{a}{b}{c} . \end{screen} The general rule is that nested sums and products are converted to flattened form if these two forms are indistinguishable in the standard output format. Nested sums and products can occur, but they have to have different or non-empty bracket types for their children. An example is \begin{screen}{0} \prod{a}{\prod(b)(c)} \end{screen} which prints as \verb|a*(b*c)|. This is not automatically converted to \verb|a*b*c|. Note that this form is \emph{not} represented as \begin{screen}{0} \prod{a}(b)(c) (wrong) \end{screen} This is a consequence of the second rule: all child nodes of product or sum nodes must have the same bracket type. In summary, automatic flattening of nested sum or product trees do not automatically occur over bracket boundaries. You can then write and keep $(\sin(x)+\cos(x)) + (\sin(x) + 3 \cos(x))$, which will be stored as \begin{screen}{0} \sum{\sum(sin(x))(cos(x))}{\sum(sin(x))(cos(x))} \end{screen} In order to remove brackets, one uses the \subscommand{sumflatten} and \subscommand{prodflatten} commands, see section~\ref{m:algebra}. Products and sums with sub- or superscripts which apply to one or more of the child nodes are internally represented using \verb|\indexbracket| nodes. That is, the input \begin{screen}{0} q (a+b)_\mu \end{screen} is represented as \begin{screen}{0} \prod{q}{\indexbracket{\sum(a)(b)}_{\mu}} \end{screen} (note the way in which the bracket types are inherited). In fact, such indexbracket constructions apply for any content inside the brackets; in the example above, an indexbracket would be generated even without the \verb|\sum| node: the input \begin{screen}{0} q (\Gamma^r)_{a b} \end{screen} is stored as \begin{screen}{0} \prod{q}{\indexbracket(\Gamma^r)_{a b}} \end{screen} The result of the indexbracket way of storing expressions is that ``index free'' manipulations apply directly inside the indexbracket argument and no special algorithms are needed. Input will automatically be converted to this form. Getting rid of indexbrackets around single symbols is done using \subscommand{remove\_indexbracket}. Another issue is the storage of numbers. Since pure numerical factors are only allowed to appear in the multiplier field of a node, a pure number is stored as ``1'' with its multiplier equal to the number. Product nodes with two arguments of which one is a number are not allowed and will be converted to a single node with multiplier field, automatically. In order to eliminate ambiguities concerning multipliers in sum and product nodes, the following rules should be obeyed: sum nodes always have unit multiplier (i.e.~non-trivial multipliers are associated to the children) and children of product nodes should also always have unit multiplier (i.e.~the multipliers of all the children should in this case be collected in the prod node itself). \subsection{External scalar engine interface} \Cdb is a tensor computer algebra system, without much functionality for simplification or manipulation of scalar expressions. Other systems exist which handle this much better, and it is a waste to duplicate those efforts. Therefore, the \cdbclass{algorithm} class contains functionality to isolate scalar factors from a tensorial expression, manipulate them using an external scalar CAS, and re-insert them into the internal \cdb tree. Scalar expressions are defined to be sums or (subsets of factors of) products which contain no objects with subscript or superscript children (i.e.~contain no tensors). Exporting a scalar expression to an external CAS requires a rewriting step before and after the export. At present only Maxima's format is supported. \vfill\eject \section{Module implementation guide} \subsection{Storage of numbers and strings} There is a special memory area for the storage of rational numbers (with arbitrary-length integers for the numerator and denominator) as well as for the storage of strings. \subsection{Accessing indices} Indices are stored as ordinary child nodes. However, there are various ways to iterate over all indices in a factor, which are more useful than a simple iteration over all child nodes. \subsection{Object properties} The properties attached to a node in the tree can be queried by using a lookup method in the {\tt properties} namespace. Object properties are child classes of the {\tt property} class, and contain the property information in a parsed form. The following code snippet illustrates how properties are dealt with: \begin{screen}{0} AntiSymmetry *s=properties::get(it) if(s) { // do something with the property info } \end{screen} Here we used a property called {\tt AntiSymmetry}, which is declared in the the module header {\tt modules/algebra.hh} (see the other header files of the various modules for information about the available property types). If the node pointed to by {\tt it} has this property associated to it, the pointer {\tt s} will be set to point to the associated property node. \bfcomment{KP}{Better to use a property example where the property node contains some additional information, which can then be used.} It is also possible to do this search in the other direction, that is, to find an object with a given property. \begin{screen}{0} properties::property_map_t::iterator it=properties::get_pattern(); if(it!=properties::props.end()) { // Now *(it->first) contains the name of a GammaMatrix object. } \end{screen} \bfcomment{KP}{Instead of checking these things, it is better to throw exceptions, since that will make the code more readable and also the error handling more uniform (it can go in one place instead of being repeated).} Sums and products inherit, in a certain way, properties of the terms and factors from which they are built up. This is true also for other functions. If you want to know whether a given node has such \emph{inherited properties}, a simple call to \verb|get<...>| is not sufficient. Instead, use the following construction: \begin{screen}{0} Matrix *m=properties::get_composite(it) if(m) { // do something with the property info } \end{screen} These inheritance rules for composite objects are at present hard-coded but will be user-defineable at a later stage. In addition to querying for object properties, some algorithms also act on objects which encode their property in a special reserved node name. As an example, the \subscommand{prodrule} acts on objects which carry a \subsprop{Derivative} property, but it also acts on \subscommand{cdb\_Derivative} objects. This allows e.g.~the \subscommand{vary} algorithm to wrap a derivative-like object around powers and have \subscommand{prodrule} expand that % \begin{sectionunit} % \title{Labelling and selection of expressions} % % % The kernel of \cdb is completely separated from its user interface, % but the communication between the two uses a human-readable format. % In order to allow the front-end to refer to individual elements of % the expressions, a simple labelling scheme is used for every % node in an expression. The \cdb kernel output thus looks like % \begin{screen}{0} % \Gamma@1_{m@2} \Gamma@3_{n@4} \Gamma@5_{p@6} % \end{screen} % All symbols have been labelled with a unique % numerical identifier. When you select the two gamma symbols, the % front-end notifies the core of this action by sending back the % identifiers ``1'' and ``3''. Upon receipt of the command {\tt @join} % the core then knows to which objects this algorithm should apply. In % the absence of a front-end, you can do the selection by hand: just % send the command {\tt @select} to the core, followed by a comma % separated bracketed argument list of numerical identifiers. There also % exist an {\tt @unselect} command. % % % \subsection{Writing a new algorithm module} \label{s:writing_new} All functionality of cadabra that goes beyond storage of the expression trees is located in separate modules, stored in the \verb|src/modules| subdirectory. New functionality can easily be added by writing new modules. All algorithm objects derive from the \verb|algorithm| object defined in \verb|src/algorithm.hh|, and only a couple of virtual members have to be implemented. \begin{figure}[p!] \begin{screen}{0} class str_node { public: ... }; \end{screen} \caption{The node class.\label{f:str_node}} \end{figure} \begin{figure}[p!] \begin{screen}{0} class algorithm { public: typedef exptree::iterator iterator; typedef exptree::sibling_iterator sibling_iterator; algorithm(exptree&, iterator&); virtual void description() const=0; virtual bool can_apply(iterator&); virtual bool can_apply(sibling_iterator&, sibling_iterator&); virtual result_t apply(iterator&); virtual result_t apply(sibling_iterator&, sibling_iterator&); sibling_iterator args_begin() const; sibling_iterator args_end() const; unsigned int number_of_args() const; exptree& tr; iterator this_command; }; \end{screen} \caption{The relevant members of the class interface for the {\tt algorithm} object. The virtual members and the constructor have to be implemented in new algorithm objects; see the main text for an explanation of the two versions of {\tt can\_apply} and {\tt apply}.} \label{f:algorithm} \end{figure} \begin{figure}[p!] \begin{screen}{0} class exptree { public: sibling_iterator arg(iterator, unsigned int) const; unsigned int arg_size(sibling_iterator) const; multiplier_t arg_to_num(sibling_iterator, unsigned int) const; }; \end{screen} \caption{The relevant members of the class interface for the {\tt exptree} object.} \end{figure} The class interface for the algorithm object is shown in figure~\ref{f:algorithm}. The members which any class derived from {\tt algorithm} should implement are described below. \begin{description} \item[{\tt constructor(exptree\&, iterator)}] Algorithm objects get initialised with a reference {\tt tr} to the expression tree on which they act, together with an iterator {\tt this\_command} pointing to the associated command node. By looking at the child nodes of the latter, the arguments of the command can be obtained. The simplest way to do this is to use the sibling iterators returned by \verb|args_begin()| and \verb|args_end()|; these automatically skip the argument which refers to the equation number (i.e.~they skip the \verb|(5)| argument in \verb|@command(5){arg1}{arg2}|). The constructor is a good place to parse the command arguments, since that will in general only be required once. Do not do anything in the constructor that has to be done on every invocation of the same command on different expressions. If you discover that the arguments passed to an algorithm are not legal, you have to throw an {\tt algorithm::constructor\_error} exception. \item[{\tt description()}] Should display an explanation of the functionality of the algorithm on the {\tt txtout} stream. Do not add \verb|std::endl| newlines by hand, these will be inserted automatically. \item[\vbox{\hbox{\tt bool can\_apply(iterator)} \hbox{\tt bool can\_apply(sibling\_iterator, sibling\_iterator)}}] Determines whether the algorithm has a chance of acting on the given expression. This is an \emph{estimate} but is required to return {\tt true} if there is a possibility that the algorithm would yield a change. It takes two sibling\_iterators as arguments, which indicate a node or a range of nodes on which the algorithm is supposed to act. Since {\tt can\_apply} is guaranteed to be called before {\tt apply}, it is allowed for the {\tt can\_apply} member to store results for later use in {\tt apply}. However, multiple calls to can be made to this combo, so any data stored should be erased upon each call to {\tt can\_apply}. \item[\vbox{\hbox{\tt apply\_result apply(iterator\&)} \hbox{\tt apply\_result apply(sibling\_iterator\&, sibling\_iterator\&)}}] This is where the actual algorithm is applied. It is allowed to modify the iterator if necessary. No elements in the tree which sit above the entry point should ever be changed. Before exiting this function, the member variable {\tt expression\_modified} has to be set according to whether or not the apply call made any changes to the expression. If the algorithm can take a long time to complete and you want to give the user the option of interrupting it with control-C, you can check (at points where the algorithm can be interrupted) the global variable {\tt interrupted}. If it is set, you should immediately throw an exception of type {\tt algorithm\_interrupted}, preferably with a short string describing the location or algorithm at which the interrupt occurred. The exception will be handled at the top level in the {\tt manipulator.cc} code, where the current expression will be removed. % %Do not forget to unset it afterwards. If you exit an %algorithm this way, your module should leave the expression tree in %exactly the same way as it was when the {\tt apply} member was %entered. Return \verb|l_error| to signal failure. Algorithms can write progress information to the stream {\tt txtout} and debug information (which will go into a separate file on disk) to {\tt debugout}. These are global objects. Do not use the \Cpp streams {\tt std::cout} and {\tt std::cerr} for this purpose. \end{description} An algorithm is \emph{never} allowed to modify the tree above the node or range of sibling nodes which were passed to the \verb|apply| call. In other words, siblings and parent nodes should never be touched, and the nodes should not be removed from the tree directly. If you want to remove nodes, this can be done by setting their multiplier field to zero; the core routines will take care of actually removing the nodes from the tree. It is allowed to inspect the tree above the given nodes, but this is discouraged. Upon any exit from an algorithm module, the tree is required to be in a valid state. In many cases, it is useful to clean up modifications to the tree by calling the utility function {\tt cleanup\_expression} (see section~\ref{s:utility} for more information). \subsection{Adding the module to the system} Once you have written the \verb|.hh| and \verb|.cc| files associated to your new algorithm, it has to be added to the build process and the core program. First, add the header to the master header file \verb|src/modules/modules.hh| file; this one looks like \begin{screen}{0} src/modules/modules.hh: #include "algebra.hh" #include "pertstring.hh" #include "select.hh" ... \end{screen} You also have to add it to the \verb|src/Makefile.in|. Near the top of this file you find a line looking somewhat like \begin{screen}{0} src/Makefile.in: ... MOBJS=modules/algebra.o modules/pertstring.o modules/convert.o \ modules/field_theory.o modules/select.o modules/dummies.o \ modules/properties.o modules/relativity.o modules/substitute.o ... \end{screen} and this is where your module has to be added. Finally, you have to make the algorithm visible to the core program. This is done in the \verb|src/manipulator.cc| file. In the constructor of the \verb|manipulator| class (defined somewhere near the top), you see a map of names to algorithm classes. A small piece is listed below: \begin{screen}{0} src/manipulator.cc: ... // pertstring algorithms["@aticksen"] =&create; algorithms["@riemannid"] =&create; // algebra algorithms["@distribute"] =&create; ... \end{screen} Add your algorithm here; it does not have to have the same name as the object class name. Once this is all done, rerun configure and make. \subsection{Adding new properties} \begin{figure}[t] \begin{screen}{0} class property\_base{ public: virtual bool parse(exptree&, iterator pat, iterator prop); virtual std::string name() const=0; virtual void display(std::ostream&) const; }; class property : public property\_base {}; class list\_property : public property\_base {}; class labelled\_property : public property { public: std::string label; }; \end{screen} \caption{The relevant members of the class interface for the {\tt property\_base} object and the derived objects.} \end{figure} \bfcomment{KP}{Discuss the various member functions of property, in particular the way in which parse is supposed to behave, and the way in which properties should be registered.} Since algorithms rely crucially on a \emph{fixed} set of properties which they provide themselves, we store these things in a \Cpp way, rather than using strings. Another motivation: we do not want to parse (and check) these property trees every time they are accessed. Properties typically carry key/value pairs which further specify the characteristics of the property. When the property object is created, the core calls the \verb|parse()| method of the property, in which you are responsible for scanning through the list of key/value pairs. This is rather simple: just call the \verb|find()| member of the \verb|keyval| argument, \begin{screen}{0} keyval_t::iterator ki=keyvals.find("dimension"); if(ki!=keyvals.end()) { // now ki->second is an iterator to an expression subtree } \end{screen} You are supposed to remove any handled keyval pair from the list by using the \verb|erase()| member, so that the system can keep track of unhandled pairs. Do not forget to call the \verb|parse()| method of all parent classes at the end. Once this is all done, register the property with the system by adding an appropriate call to the module's \verb|register_properties()| method, found at the top of each module. \subsection{Throwing errors} If, at any stage, an inconsistent expression is encountered, the safe way to return to the top level of the manipulator is to throw the exception class \cdbclass{consistency\_error} (defined in \cdbfile{algorithm.hh}). \subsection{Manipulating the expression tree} The \cdbclass{exptree} class contains a number of tree access routines which enhance the functionality of the {\tt tree.hh} library. \begin{description} \item[\member{index\_iterator}] \item[\member{index\_map\_t}] \end{description} \subsubsection{Acting on products or single terms} use \member{is\_single\_term} inside \member{can\_apply} to test for this case. Then in \member{apply} call \member{prod\_wrap\_single\_term} (which will be harmless for proper products). At the very end of \member{apply}, call \member{prod\_unwrap\_single\_term} to remove the product again. \subsection{Utility functions} \label{s:utility} There are also various useful helper functions in the {\tt exptree} class, mainly dealing with the conversion of expression numbers or labels to iterators that point to the actual expression in the tree. \begin{description} \item[\vbox{\hbox{\member{cleanup\_expression(exptree\&)}} \hbox{\member{cleanup\_expression(exptree\&, iterator)}}}] Converts an expression (or part of it below the indicated node) to a valid form. That is, it calls various simplification algorithms on the expression, among which {\tt sumflatten} and {\tt prodcollectnum}. \item[\member{cleanup\_nests}] When called on a product inside a product, or a sum inside a sum, and the bracket types of both node and parent are the same, flatten the tree. Adjusts the iterator to point to the product or sum node which remains. \item[\member{equation\_by\_number\_or\_name}] Given an iterator to a node that represents an expression number or expression label, this member returns an iterator that points to the actual node (to be precise: to the \verb|\history| node of the expression). \item[\vbox{\hbox{\member{arg\_size(sibling\_iterator)}} \hbox{\member{arg(iterator, unsigned int)}}}] Many algorithms require one \emph{or more} objects as arguments. These are usually passed as lists, and therefore end up being of two forms: either they are single objects or they are {\tt comma} objects representing a list. In order to avoid having to check for these two cases, one can use these two member functions. The iterator arguments of these two member functions should point to the child which is either a single argument or a \texcommand{comma} node. \item[\member{pushup\_multiplier}] Can be called on any node. If the node has a non-unit multiplier and the storage conventions exclude this, the algorithm will push the multiplier up the tree. \end{description} % \begin{itemize} % \item The various comparison functions in str\_node. % \item Members of active\_node and algorithm. % \item Multiply, add, zero and one in these classes. % \end{itemize} \subsection{Writing a new output module} \kcomment{KP}{Structure is different now: one inherits from {\tt output\_exptree} and then has printing stuff at ones disposal. Still would be nice to be able to change the printing objects for a given node type, i.e.~modify the map of node names to printing objects.} \kcomment{KP}{Also do something intelligent with the Mathematica output flags}. \subsection{Namespaces and global objects} The following objects are global: \begin{description} \item[{\tt modglue::opipe txtout}] The normal output stream, to which you should communicate with the user. \item[{\tt std::ofstream debugout}] The debug output stream, which normally writes to a file, and should only be used to write output which is useful for debugging purposes. \item[{\tt nset\_t name\_set}] The global collection of all strings. Nodes in the expression tree contain an iterator into this map (see in particular figure~\ref{f:str_node}). \item[{\tt rset\_t rat\_set}] The global collection of all rational numbers. Nodes in the expression tree contain an iterator into this map (see in particular figure~\ref{f:str_node}). \item[{\tt bool interrupted}] A global flag which indicates that the user has requested the computation to be interrupted. See section~\ref{s:writing_new} for more information on this variable. \item[{\tt stopwatch globaltime}] The wall time since program start. \item[{\tt unsigned int size\_x, size\_y}] The size of the current output window. \end{description} % \subsection{Troubleshooting} % % \begin{description} % \item[Problems getting expressions in canonical form] % There are various canonical places to look for errors. One of % them is the routine {\tt propagate\_zeroes}, which may still not remove % zeroes properly but leave an inconsistent tree. Another place % is {\tt cleanup\_nests}. % \end{description} \vfill\eject % \section{Future plans} % \subsection{Front-ends} % % % %The text-mode front-end will be based on {\tt eqascii} by % %\dcite{e_bori1}, while the graphical front-end will use % %\TeX{} for typesetting. % % \subsection{Component calculations} %\vfill\eject % \begin{sectionunit} % \title{Using the history mechanism} % % Let us first discuss an example which shows the way in which the \cdb % history mechanism works, and also exhibits the selection mechanism. % As with all other data structures in \cdb, the history is also a % tree-like structure. Expressions and commands get appended as children % of each other. When you backtrack by going to a previous expression in % the history, any new commands get added as child, thereby keeping % the previous calculations based on that node accessible. An % example illustrates how this works. % \begin{screen}{0} % > \Gamma_{m} \Gamma_{n} % (1) : \Gamma_{m} \Gamma_{n} % > @join{(1), 1, 2} % (1) : \Gamma_{m n} + \eta_{m n} % > \Gamma_{m n} = \epsilon_{p q r s} \Gamma^{p q r s} \tilde\Gamma % (1) : \Gamma_{m n} + \eta_{m n} % (2) : \Gamma_{m n} = \epsilon_{p q r s m n} \Gamma^{p q r s} \tilde\Gamma % > @subs{(2), (1)} % (1) : \epsilon_{p q r s m n}\Gamma^{p q r s}\tilde\Gamma + \eta_{m n} % (2) : \Gamma_{m n} = \epsilon_{p q r s} \Gamma^{p q r s} \tilde\Gamma % > \eta_{m n} = 0 % (1) : \epsilon_{p q r s m n}\Gamma^{p q r s}\tilde\Gamma + \eta_{m n} % (2) : \Gamma_{m n} = \epsilon_{p q r s} \Gamma^{p q r s} \tilde\Gamma % (3) : \eta_{m n} = 0 % > @up((1)) % (1) : \Gamma_{m n} + \eta_{m n} % > @subs{(3), (1)} % (1) : \Gamma_{m n} % (2) : \Gamma_{m n} = \epsilon_{p q r s} \Gamma^{p q r s} \tilde\Gamma % (3) : \eta_{m n} = 0 % \end{screen} % Notice how the modification of equation~(1) has produced a new % equation, but it has kept the original expression in memory as well. % You can see the history of an equation by doing % \begin{screen}{0} % > @showtree((1)) % input % (1) : \Gamma_{m} \Gamma_{n} % join % (1.1) : \Gamma_{m n} + \eta_{m n} % subs % (1.1.1) : \epsilon_{p q r s m n}\Gamma^{p q r s}\tilde\Gamma + \eta_{m n} % subs % (1.1.2)*: \Gamma_{m n} % \end{screen} % The star indicates which equation is currently denoted with~(1) in the % compact output. If you are not interested in the paths that led to % other expressions, then it is sufficient to do % \begin{screen}{0} % > @showhistory((1)) % input : \Gamma_{m} \Gamma_{n} % join : \Gamma_{m n} + \eta_{m n} % subs : \Gamma_{m n} % \end{screen} % This can be used to generate a clean report of all the manipulations % that lead up to a certain result. If you are confident that you do not % anymore need any of the branches except the one that leads to the % last result, you can enter the \verb|@cleanhistory| command. % \printindex \bibliographystyle{kasper} \bibliography{kasbib} \end{document} % \begin{sectionunit} % \title{Cursor mode} % % At any time, pressing `escape' will jump to the `cursor' mode. In this % mode, one can select and unselects parts of the expression. Available % commands: % \begin{center} % \begin{tabular}{ll} % cursor-right & move cursor to next object on this level \\[1ex] % cursor-left & move cursor to previous object on this level \\[1ex] % cursor-down & move cursor to the arguments of the current % objects\\[1ex] % cursor-up & move cursor to the parent of the current object\\[1ex] % page-down & enlarge cursor size \\[1ex] % page-up & shrink cursor size \\[1ex] % e & remove all selections \\[1ex] % space & select the objects currently under the cursor % \end{tabular} % \end{center} % \begin{enumerate} \item Work both with abstract component tensors as well as individual components. The algorithms for e.g.~gamma matrix manipulation have to recognise this (not just flip indices around, but actually use $\Gamma^1 \Gamma^1=1$ and so on). \end{enumerate} cadabra-1.39/doc/combinatorics.tex000066400000000000000000000066531234107666300171700ustar00rootroot00000000000000\documentclass[11pt]{kasper} \usepackage{relsize} \begin{document} \title{{\tt combinatorics.hh} documentation} \author{Kasper Peeters} \address{1}{{\it MPI/AEI f\"ur Gravitationsphysik, Am M\"uhlenberg 1, 14476 Potsdam, Germany}} \email{k.peeters@damtp.cam.ac.uk} \maketitle \begin{abstract} The {\tt combinatorics.hh} class is bla bla \end{abstract} \begin{sectionunit} \title{Reference guide} \maketitle The {\tt combinatorics.hh} class library contains two classes for the generation of combinations \begin{sectionunit} \title{The {\tt combinations} class} \maketitle The {\tt combinations} class takes a vector of elements, and generates combinations of a subset of these elements that satisfy several requirements. \begin{description} \item[{\tt sublengths}]~\\ Stores the lengths of the object ranges in which objects can only appear in increasing order. The usual concepts of ``combinations and permutations'' translate to the following content of the {\tt sublengths} vector: \begin{equation} \begin{aligned} \text{combinations:} &\quad \text{one element, $v$=total length}\, ,\\ \text{permutations:} &\quad \text{$n$ elements, all equal to $1$}. \end{aligned} \end{equation} However, many more general situations are possible with {\tt combinatorics.hh}. See the examples below. \item[{\tt input\_asym}] ~\\ Stores sets of objects which have to be ``implicitly permuted''. That is, permutations are done only modulo the permutations of the objects in these sets. An example may help: \begin{equation} \begin{aligned} \{a,b,c\} &\rightarrow \frac{1}{6}(a,b,c + a,c,b + b,a,c + c,a,b + b,c,a + c,b,a)\\ \{a,b,c\}_{\{0,1\}} &\rightarrow \frac{1}{3}(a,b,c + a,c,b + c,a,b)\\ \{a,b,c\}_{\{0,2\}} &\rightarrow \frac{1}{3}(a,b,c + a,c,b + b,a,c)\\ \{a,b,c\}^{\{2,1\}} &\rightarrow \frac{1}{3}(a,b,c + a,c,b + c,a,b) \end{aligned} \end{equation} Note that this does not just remove terms, it also corrects the multiplicative factor. \end{description} \end{sectionunit} \begin{sectionunit} \title{The {\tt symmetriser} class} \maketitle The {\tt symmetriser} class takes a vector of elements, and applies permutations or combinations to it. The difference with {\tt combinations} is that {\tt symmetriser} can be used to apply several permutations successively. Here is an example, \begin{screen} symmetriser sm; sm.original.push_back("r1"); sm.original.push_back("r2"); sm.original.push_back("r3"); sm.original.push_back("r4"); sm.original.push_back("r5"); sm.block_length=1; sm.permutation_sign=-1; sm.permute_blocks.push_back(1); sm.permute_blocks.push_back(2); sm.apply_symmetry(); \end{screen} This permutes the {\tt r2} and {\tt r3} items, with a minus sign under exchange, leaving the other elements unchanged. \begin{description} \item[set storage] \item[result storage] \item[permuting by position] \item[permuting by value] \item[weights] \item[input symmetries] Just as with the {\tt combinations} class, the {\tt symmetriser} class can be told to apply symmetries only modulo given symmetries. Take care when permuting objects by value: the \verb|input\_asym| data still refer to object locations, not object values (this may be a tricky bug to find when you are permuting integers). The object locations are always relative to the set of permuted values, not with respect to the complete set of original values. \end{description} \end{sectionunit} \end{sectionunit} \begin{sectionunit} \title{Examples} \maketitle \end{sectionunit} \end{document} cadabra-1.39/doc/components.tex000066400000000000000000000023301234107666300165050ustar00rootroot00000000000000 \section{Component expansion} # algorithm: # # - need to cache information because there are potentially many operations # - need to canonicalise indices # # Eval first works at C_{\alpha} level. # # # Estimates: # # Kretschmann in 10d: 10^4 values to sum over. So we need to be able to cut # this down to the non-zero ones early: as soon as a zero combination is found # for one of the factors, remove this branch of the search tree. # Need to: # a) make the algorithm work at the top, recursively down, since we need to keep memory/cache of already evaluated objects. # b) for all levels recursively visited, determine whether substitution # rules fix the value (hence allowing D_1 + E_1 -> 3 even if E_1 is # not known as a component. # c) use a 'base n' type notation to map an index value combination for # an n-valent tensor to an integer, so that we can make a map from # integers to expressions for any tensor, avoiding repeated substitutions. # # A_m ( B_m + C_m ) D_n Q_n: # # - collect free and dummy indices. # - do a depth-first walk # - for each node, determine the index values for which # a rule is available cadabra-1.39/doc/doxygen_cadabra.config000066400000000000000000001773571234107666300201250ustar00rootroot00000000000000# Doxyfile 1.5.8 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = cadabra # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = "1.x" # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = doxygen # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Farsi, Finnish, French, German, Greek, # Hungarian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, Polish, # Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, Slovene, # Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = /home/kasper/git/cadabra/src/ # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = /home/kasper/git/cadabra/src/ # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it parses. # With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this tag. # The format is ext=language, where ext is a file extension, and language is one of # the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP, # Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat # .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran), # use: inc=Fortran f=C EXTENSION_MAPPING = # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen to replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penality. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will rougly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = YES # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = YES # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = YES # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by # doxygen. The layout file controls the global structure of the generated output files # in an output format independent way. The create the layout file that represents # doxygen's defaults, run doxygen with the -l option. You can optionally specify a # file name after the option, if omitted DoxygenLayout.xml will be used as the name # of the layout file. LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = ../src # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.d \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.idl \ *.odl \ *.cs \ *.php \ *.php3 \ *.inc \ *.m \ *.mm \ *.dox \ *.C \ *.CC \ *.C++ \ *.II \ *.I++ \ *.H \ *.HH \ *.H++ \ *.CS \ *.PHP \ *.PHP3 \ *.M \ *.MM # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = ../src/tree.hh \ ../src/tree_util.hh \ ../src/tree_new.hh \ ../src/tree_msvc.hh # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = NO # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = YES # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER # are set, an additional index file will be generated that can be used as input for # Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated # HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add. # For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's # filter section matches. # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to FRAME, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. Other possible values # for this tag are: HIERARCHIES, which will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list; # ALL, which combines the behavior of FRAME and HIERARCHIES; and NONE, which # disables this behavior completely. For backwards compatibility with previous # releases of Doxygen, the values YES and NO are equivalent to FRAME and NONE # respectively. GENERATE_TREEVIEW = YES # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = YES # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES # By default doxygen will write a font called FreeSans.ttf to the output # directory and reference it in all dot files that doxygen generates. This # font does not include all possible unicode characters however, so when you need # these (or just want a differently looking font) you can specify the font name # using DOT_FONTNAME. You need need to make sure dot is able to find the font, # which can be done by putting it in a standard location or by setting the # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory # containing the font. DOT_FONTNAME = FreeSans # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the output directory to look for the # FreeSans.ttf font (which doxygen will put there itself). If you specify a # different font using DOT_FONTNAME you can set the path where dot # can find it using this tag. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = NO # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = NO # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = NO # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 1000 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Options related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO cadabra-1.39/doc/doxygen_tree.config000066400000000000000000000233361234107666300174720ustar00rootroot00000000000000# Doxyfile 1.4.4 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- PROJECT_NAME = tree PROJECT_NUMBER = "release 2.0" OUTPUT_DIRECTORY = doxygen CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English USE_WINDOWS_ENCODING = NO BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = "The $name class" \ "The $name widget" \ "The $name file" \ is \ provides \ specifies \ contains \ represents \ a \ an \ the ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO DETAILS_AT_TOP = NO INHERIT_DOCS = YES DISTRIBUTE_GROUP_DOC = NO SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 8 ALIASES = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = YES EXTRACT_PRIVATE = YES EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO HIDE_UNDOC_MEMBERS = YES HIDE_UNDOC_CLASSES = YES HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = YES HIDE_SCOPE_NAMES = NO SHOW_INCLUDE_FILES = YES INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_BY_SCOPE_NAME = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_DIRECTORIES = YES FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- INPUT = tree.hh FILE_PATTERNS = *.c \ *.cc \ *.cxx \ *.cpp \ *.c++ \ *.d \ *.java \ *.ii \ *.ixx \ *.ipp \ *.i++ \ *.inl \ *.h \ *.hh \ *.hxx \ *.hpp \ *.h++ \ *.idl \ *.odl \ *.cs \ *.php \ *.php3 \ *.inc \ *.m \ *.mm \ *.dox \ *.C \ *.CC \ *.C++ \ *.II \ *.I++ \ *.H \ *.HH \ *.H++ \ *.CS \ *.PHP \ *.PHP3 \ *.M \ *.MM RECURSIVE = NO EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXAMPLE_PATH = EXAMPLE_PATTERNS = * EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO USE_HTAGS = NO VERBATIM_HEADERS = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = NO COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_ALIGN_MEMBERS = YES GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO BINARY_TOC = NO TOC_EXPAND = NO DISABLE_INDEX = NO ENUM_VALUES_PER_LINE = 4 GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = YES LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4wide EXTRA_PACKAGES = LATEX_HEADER = PDF_HYPERLINKS = NO USE_PDFLATEX = NO LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_SCHEMA = XML_DTD = XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png DOT_PATH = DOTFILE_DIRS = MAX_DOT_GRAPH_WIDTH = 1024 MAX_DOT_GRAPH_HEIGHT = 1024 MAX_DOT_GRAPH_DEPTH = 1000 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- SEARCHENGINE = NO cadabra-1.39/doc/exp1.eps000066400000000000000000000106531234107666300151730ustar00rootroot00000000000000%!PS-Adobe-2.0 EPSF-2.0 %%Title: exp1.fig %%Creator: fig2dev Version 3.2 Patchlevel 5-alpha7 %%CreationDate: Sun Jul 30 23:11:05 2006 %%BoundingBox: 0 0 213 153 %Magnification: 1.0000 %%EndComments /$F2psDict 200 dict def $F2psDict begin $F2psDict /mtrx matrix put /col-1 {0 setgray} bind def /col0 {0.000 0.000 0.000 srgb} bind def /col1 {0.000 0.000 1.000 srgb} bind def /col2 {0.000 1.000 0.000 srgb} bind def /col3 {0.000 1.000 1.000 srgb} bind def /col4 {1.000 0.000 0.000 srgb} bind def /col5 {1.000 0.000 1.000 srgb} bind def /col6 {1.000 1.000 0.000 srgb} bind def /col7 {1.000 1.000 1.000 srgb} bind def /col8 {0.000 0.000 0.560 srgb} bind def /col9 {0.000 0.000 0.690 srgb} bind def /col10 {0.000 0.000 0.820 srgb} bind def /col11 {0.530 0.810 1.000 srgb} bind def /col12 {0.000 0.560 0.000 srgb} bind def /col13 {0.000 0.690 0.000 srgb} bind def /col14 {0.000 0.820 0.000 srgb} bind def /col15 {0.000 0.560 0.560 srgb} bind def /col16 {0.000 0.690 0.690 srgb} bind def /col17 {0.000 0.820 0.820 srgb} bind def /col18 {0.560 0.000 0.000 srgb} bind def /col19 {0.690 0.000 0.000 srgb} bind def /col20 {0.820 0.000 0.000 srgb} bind def /col21 {0.560 0.000 0.560 srgb} bind def /col22 {0.690 0.000 0.690 srgb} bind def /col23 {0.820 0.000 0.820 srgb} bind def /col24 {0.500 0.190 0.000 srgb} bind def /col25 {0.630 0.250 0.000 srgb} bind def /col26 {0.750 0.380 0.000 srgb} bind def /col27 {1.000 0.500 0.500 srgb} bind def /col28 {1.000 0.630 0.630 srgb} bind def /col29 {1.000 0.750 0.750 srgb} bind def /col30 {1.000 0.880 0.880 srgb} bind def /col31 {1.000 0.840 0.000 srgb} bind def end save newpath 0 153 moveto 0 0 lineto 213 0 lineto 213 153 lineto closepath clip newpath -101.1 312.8 translate 1 -1 scale /cp {closepath} bind def /ef {eofill} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth} bind def /tr {translate} bind def /tnt {dup dup currentrgbcolor 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} bind def /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 4 -2 roll mul srgb} bind def /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def /$F2psEnd {$F2psEnteredState restore end} def $F2psBegin 10 setmiterlimit 0 slj 0 slc 0.06299 0.06299 sc % % Fig objects follow % % % here starts figure with depth 50 % Polyline 0 slj 0 slc 7.500 slw n 4410 2790 m 3825 2925 l gs col0 s gr % Polyline n 4410 2790 m 4905 2925 l gs col0 s gr % Polyline n 3690 3240 m 3150 3375 l gs col0 s gr % Polyline n 3690 3240 m 4140 3375 l gs col0 s gr % Polyline n 3015 3645 m 2655 3825 l gs col0 s gr % Polyline n 3015 3645 m 3465 3825 l gs col0 s gr % Polyline n 2610 4140 m 3015 4275 l gs col0 s gr % Polyline n 2115 4590 m 2115 4770 l gs col0 s gr % Polyline n 2115 4590 m 1755 4770 l gs col0 s gr % Polyline n 2115 4590 m 2520 4770 l gs col0 s gr % Polyline n 3015 4590 m 3015 4770 l gs col0 s gr % Polyline n 4095 3690 m 4095 3870 l gs col0 s gr % Polyline n 2610 4140 m 2160 4275 l gs col0 s gr /Times-Roman ff 190.50 scf sf 3600 3150 m gs 1 -1 sc (prod) col0 sh gr /Times-Roman ff 190.50 scf sf 4050 3600 m gs 1 -1 sc (psi) col0 sh gr /Times-Roman ff 190.50 scf sf 4860 3150 m gs 1 -1 sc (x) col0 sh gr /Times-Roman ff 190.50 scf sf 2970 3600 m gs 1 -1 sc (diff) col0 sh gr /Times-Roman ff 190.50 scf sf 2070 4500 m gs 1 -1 sc (F) col0 sh gr /Times-Roman ff 190.50 scf sf 1620 4950 m gs 1 -1 sc (mu) col0 sh gr /Times-Roman ff 190.50 scf sf 2070 4950 m gs 1 -1 sc (nu) col0 sh gr /Times-Roman ff 190.50 scf sf 2430 4950 m gs 1 -1 sc (rho) col0 sh gr /Times-Roman ff 190.50 scf sf 2970 4500 m gs 1 -1 sc (psi) col0 sh gr /Times-Roman ff 190.50 scf sf 2430 4050 m gs 1 -1 sc (prod) col0 sh gr /Times-Roman ff 190.50 scf sf 2970 4950 m gs 1 -1 sc (mu) col0 sh gr /Times-Roman ff 190.50 scf sf 4050 4050 m gs 1 -1 sc (nu) col0 sh gr /Times-Roman ff 190.50 scf sf 4320 2700 m gs 1 -1 sc (int) col0 sh gr /Times-Roman ff 190.50 scf sf 3375 4050 m gs 1 -1 sc (lam) col0 sh gr % here ends figure; $F2psEnd rs showpage %%Trailer %EOF cadabra-1.39/doc/exp1.fig000066400000000000000000000031341234107666300151450ustar00rootroot00000000000000#FIG 3.2 Produced by xfig version 3.2.5-alpha5 Portrait Center Metric A4 100.00 Single -2 1200 2 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 4410 2790 3825 2925 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 4410 2790 4905 2925 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 3690 3240 3150 3375 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 3690 3240 4140 3375 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 3015 3645 2655 3825 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 3015 3645 3465 3825 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 2610 4140 3015 4275 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 2115 4590 2115 4770 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 2115 4590 1755 4770 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 2115 4590 2520 4770 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 3015 4590 3015 4770 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 4095 3690 4095 3870 2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2 2610 4140 2160 4275 4 0 0 50 -1 0 12 0.0000 4 180 375 3600 3150 prod\001 4 0 0 50 -1 0 12 0.0000 4 180 240 4050 3600 psi\001 4 0 0 50 -1 0 12 0.0000 4 90 105 4860 3150 x\001 4 0 0 50 -1 0 12 0.0000 4 135 285 2970 3600 diff\001 4 0 0 50 -1 0 12 0.0000 4 135 105 2070 4500 F\001 4 0 0 50 -1 0 12 0.0000 4 90 255 1620 4950 mu\001 4 0 0 50 -1 0 12 0.0000 4 90 210 2070 4950 nu\001 4 0 0 50 -1 0 12 0.0000 4 135 270 2430 4950 rho\001 4 0 0 50 -1 0 12 0.0000 4 180 240 2970 4500 psi\001 4 0 0 50 -1 0 12 0.0000 4 180 375 2430 4050 prod\001 4 0 0 50 -1 0 12 0.0000 4 90 255 2970 4950 mu\001 4 0 0 50 -1 0 12 0.0000 4 90 210 4050 4050 nu\001 4 0 0 50 -1 0 12 0.0000 4 135 225 4320 2700 int\001 4 0 0 50 -1 0 12 0.0000 4 135 300 3375 4050 lam\001 cadabra-1.39/doc/exp2.eps000066400000000000000000001201761234107666300151760ustar00rootroot00000000000000%!PS-Adobe-2.0 EPSF-2.0 %%Creator: dvips(k) 5.95a Copyright 2005 Radical Eye Software %%Title: /home/kasper/tmp/kt_temp/kt_temp_makefig/makefig.dvi %%BoundingBox: 80 572 300 721 %%DocumentFonts: CMR10 CMMI10 CMMI7 %%EndComments %DVIPSWebPage: (www.radicaleye.com) %DVIPSCommandLine: dvips -E %+ /home/kasper/tmp/kt_temp/kt_temp_makefig/makefig.dvi -o exp2.eps %DVIPSParameters: dpi=600 %DVIPSSource: TeX output 2006.12.11:1148 %%BeginProcSet: tex.pro 0 0 %! /TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72 mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0 0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{ landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[ matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{ statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0] N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin /FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array /BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2 array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get }B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub} B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr 1 add N}if}B/CharBuilder{save 3 1 roll S A/base get 2 index get S /BitMaps get S get/Cd X pop/ctr 0 N Cdx 0 Cx Cy Ch sub Cx Cw add Cy setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx sub Cy .1 sub]{Ci}imagemask restore}B/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn /BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put }if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{ bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{ SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{ userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X 1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4 index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N /p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{ /Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT) (LaserWriter 16/600)]{A length product length le{A length product exch 0 exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot} imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M} B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{ p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end %%EndProcSet %%BeginProcSet: psfrag.pro 0 0 %% %% This is file `psfrag.pro', %% generated with the docstrip utility. %% %% The original source files were: %% %% psfrag.dtx (with options: `filepro') %% %% Copyright (c) 1996 Craig Barratt, Michael C. Grant, and David Carlisle. %% All rights reserved. %% %% This file is part of the PSfrag package. %% userdict begin /PSfragLib 90 dict def /PSfragDict 6 dict def /PSfrag { PSfragLib begin load exec end } bind def end PSfragLib begin /RO /readonly load def /CP /currentpoint load def /CM /currentmatrix load def /B { bind RO def } bind def /X { exch def } B /MD { { X } forall } B /OE { end exec PSfragLib begin } B /S false def /tstr 8 string def /islev2 { languagelevel } stopped { false } { 2 ge } ifelse def [ /sM /tM /srcM /dstM /dM /idM /srcFM /dstFM ] { matrix def } forall sM currentmatrix RO pop dM defaultmatrix RO idM invertmatrix RO pop srcFM identmatrix pop /Hide { gsave { CP } stopped not newpath clip { moveto } if } B /Unhide { { CP } stopped not grestore { moveto } if } B /setrepl islev2 {{ /glob currentglobal def true setglobal array astore globaldict exch /PSfrags exch put glob setglobal }} {{ array astore /PSfrags X }} ifelse B /getrepl islev2 {{ globaldict /PSfrags get aload length }} {{ PSfrags aload length }} ifelse B /convert { /src X src length string /c 0 def src length { dup c src c get dup 32 lt { pop 32 } if put /c c 1 add def } repeat } B /Begin { /saver save def srcFM exch 3 exch put 0 ne /debugMode X 0 setrepl dup /S exch dict def { S 3 1 roll exch convert exch put } repeat srcM CM dup invertmatrix pop mark { currentdict { end } stopped { pop exit } if } loop PSfragDict counttomark { begin } repeat pop } B /End { mark { currentdict end dup PSfragDict eq { pop exit } if } loop counttomark { begin } repeat pop getrepl saver restore 7 idiv dup /S exch dict def { 6 array astore /mtrx X tstr cvs /K X S K [ S K known { S K get aload pop } if mtrx ] put } repeat } B /Place { tstr cvs /K X S K known { bind /proc X tM CM pop CP /cY X /cX X 0 0 transform idtransform neg /aY X neg /aX X S K get dup length /maxiter X /iter 1 def { iter maxiter ne { /saver save def } if tM setmatrix aX aY translate [ exch aload pop idtransform ] concat cX neg cY neg translate cX cY moveto /proc load OE iter maxiter ne { saver restore /iter iter 1 add def } if } forall /noXY { CP /cY X /cX X } stopped def tM setmatrix noXY { newpath } { cX cY moveto } ifelse } { Hide OE Unhide } ifelse } B /normalize { 2 index dup mul 2 index dup mul add sqrt div dup 4 -1 roll exch mul 3 1 roll mul } B /replace { aload pop MD CP /bY X /lX X gsave sM setmatrix str stringwidth abs exch abs add dup 0 eq { pop } { 360 exch div dup scale } ifelse lX neg bY neg translate newpath lX bY moveto str { /ch X ( ) dup 0 ch put false charpath ch Kproc } forall flattenpath pathbbox [ /uY /uX /lY /lX ] MD CP grestore moveto currentfont /FontMatrix get dstFM copy dup 0 get 0 lt { uX lX /uX X /lX X } if 3 get 0 lt { uY lY /uY X /lY X } if /cX uX lX add 0.5 mul def /cY uY lY add 0.5 mul def debugMode { gsave 0 setgray 1 setlinewidth lX lY moveto lX uY lineto uX uY lineto uX lY lineto closepath lX bY moveto uX bY lineto lX cY moveto uX cY lineto cX lY moveto cX uY lineto stroke grestore } if dstFM dup invertmatrix dstM CM srcM 2 { dstM concatmatrix } repeat pop getrepl /temp X S str convert get { aload pop [ /rot /scl /loc /K ] MD /aX cX def /aY cY def loc { dup 66 eq { /aY bY def } { % B dup 98 eq { /aY lY def } { % b dup 108 eq { /aX lX def } { % l dup 114 eq { /aX uX def } { % r dup 116 eq { /aY uY def } % t if } ifelse } ifelse } ifelse } ifelse pop } forall K srcFM rot tM rotate dstM 2 { tM concatmatrix } repeat aload pop pop pop 2 { scl normalize 4 2 roll } repeat aX aY transform /temp temp 7 add def } forall temp setrepl } B /Rif { S 3 index convert known { pop replace } { exch pop OE } ifelse } B /XA { bind [ /Kproc /str } B /XC { ] 2 array astore def } B /xs { pop } XA XC /xks { /kern load OE } XA /kern XC /xas { pop ax ay rmoveto } XA /ay /ax XC /xws { c eq { cx cy rmoveto } if } XA /c /cy /cx XC /xaws { ax ay rmoveto c eq { cx cy rmoveto } if } XA /ay /ax /c /cy /cx XC /raws { xaws { awidthshow } Rif } B /rws { xws { widthshow } Rif } B /rks { xks { kshow } Rif } B /ras { xas { ashow } Rif } B /rs { xs { show } Rif } B /rrs { getrepl dup 2 add -1 roll //restore exec setrepl } B PSfragDict begin islev2 not { /restore { /rrs PSfrag } B } if /show { /rs PSfrag } B /kshow { /rks PSfrag } B /ashow { /ras PSfrag } B /widthshow { /rws PSfrag } B /awidthshow { /raws PSfrag } B end PSfragDict RO pop end %%EndProcSet %%BeginProcSet: texps.pro 0 0 %! TeXDict begin/rf{findfont dup length 1 add dict begin{1 index/FID ne 2 index/UniqueID ne and{def}{pop pop}ifelse}forall[1 index 0 6 -1 roll exec 0 exch 5 -1 roll VResolution Resolution div mul neg 0 0]FontType 0 ne{/Metrics exch def dict begin Encoding{exch dup type/integertype ne{ pop pop 1 sub dup 0 le{pop}{[}ifelse}{FontMatrix 0 get div Metrics 0 get div def}ifelse}forall Metrics/Metrics currentdict end def}{{1 index type /nametype eq{exit}if exch pop}loop}ifelse[2 index currentdict end definefont 3 -1 roll makefont/setfont cvx]cvx def}def/ObliqueSlant{dup sin S cos div neg}B/SlantFont{4 index mul add}def/ExtendFont{3 -1 roll mul exch}def/ReEncodeFont{CharStrings rcheck{/Encoding false def dup[ exch{dup CharStrings exch known not{pop/.notdef/Encoding true def}if} forall Encoding{]exch pop}{cleartomark}ifelse}if/Encoding exch def}def end %%EndProcSet %%BeginProcSet: special.pro 0 0 %! TeXDict begin/SDict 200 dict N SDict begin/@SpecialDefaults{/hs 612 N /vs 792 N/ho 0 N/vo 0 N/hsc 1 N/vsc 1 N/ang 0 N/CLIP 0 N/rwiSeen false N /rhiSeen false N/letter{}N/note{}N/a4{}N/legal{}N}B/@scaleunit 100 N /@hscale{@scaleunit div/hsc X}B/@vscale{@scaleunit div/vsc X}B/@hsize{ /hs X/CLIP 1 N}B/@vsize{/vs X/CLIP 1 N}B/@clip{/CLIP 2 N}B/@hoffset{/ho X}B/@voffset{/vo X}B/@angle{/ang X}B/@rwi{10 div/rwi X/rwiSeen true N}B /@rhi{10 div/rhi X/rhiSeen true N}B/@llx{/llx X}B/@lly{/lly X}B/@urx{ /urx X}B/@ury{/ury X}B/magscale true def end/@MacSetUp{userdict/md known {userdict/md get type/dicttype eq{userdict begin md length 10 add md maxlength ge{/md md dup length 20 add dict copy def}if end md begin /letter{}N/note{}N/legal{}N/od{txpose 1 0 mtx defaultmatrix dtransform S atan/pa X newpath clippath mark{transform{itransform moveto}}{transform{ itransform lineto}}{6 -2 roll transform 6 -2 roll transform 6 -2 roll transform{itransform 6 2 roll itransform 6 2 roll itransform 6 2 roll curveto}}{{closepath}}pathforall newpath counttomark array astore/gc xdf pop ct 39 0 put 10 fz 0 fs 2 F/|______Courier fnt invertflag{PaintBlack} if}N/txpose{pxs pys scale ppr aload pop por{noflips{pop S neg S TR pop 1 -1 scale}if xflip yflip and{pop S neg S TR 180 rotate 1 -1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg TR}if xflip yflip not and{pop S neg S TR pop 180 rotate ppr 3 get ppr 1 get neg sub neg 0 TR}if yflip xflip not and{ppr 1 get neg ppr 0 get neg TR}if}{ noflips{TR pop pop 270 rotate 1 -1 scale}if xflip yflip and{TR pop pop 90 rotate 1 -1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg TR}if xflip yflip not and{TR pop pop 90 rotate ppr 3 get ppr 1 get neg sub neg 0 TR}if yflip xflip not and{TR pop pop 270 rotate ppr 2 get ppr 0 get neg sub neg 0 S TR}if}ifelse scaleby96{ppr aload pop 4 -1 roll add 2 div 3 1 roll add 2 div 2 copy TR .96 dup scale neg S neg S TR}if}N/cp{pop pop showpage pm restore}N end}if}if}N/normalscale{ Resolution 72 div VResolution 72 div neg scale magscale{DVImag dup scale }if 0 setgray}N/psfts{S 65781.76 div N}N/startTexFig{/psf$SavedState save N userdict maxlength dict begin/magscale true def normalscale currentpoint TR/psf$ury psfts/psf$urx psfts/psf$lly psfts/psf$llx psfts /psf$y psfts/psf$x psfts currentpoint/psf$cy X/psf$cx X/psf$sx psf$x psf$urx psf$llx sub div N/psf$sy psf$y psf$ury psf$lly sub div N psf$sx psf$sy scale psf$cx psf$sx div psf$llx sub psf$cy psf$sy div psf$ury sub TR/showpage{}N/erasepage{}N/setpagedevice{pop}N/copypage{}N/p 3 def @MacSetUp}N/doclip{psf$llx psf$lly psf$urx psf$ury currentpoint 6 2 roll newpath 4 copy 4 2 roll moveto 6 -1 roll S lineto S lineto S lineto closepath clip newpath moveto}N/endTexFig{end psf$SavedState restore}N /@beginspecial{SDict begin/SpecialSave save N gsave normalscale currentpoint TR @SpecialDefaults count/ocount X/dcount countdictstack N} N/@setspecial{CLIP 1 eq{newpath 0 0 moveto hs 0 rlineto 0 vs rlineto hs neg 0 rlineto closepath clip}if ho vo TR hsc vsc scale ang rotate rwiSeen{rwi urx llx sub div rhiSeen{rhi ury lly sub div}{dup}ifelse scale llx neg lly neg TR}{rhiSeen{rhi ury lly sub div dup scale llx neg lly neg TR}if}ifelse CLIP 2 eq{newpath llx lly moveto urx lly lineto urx ury lineto llx ury lineto closepath clip}if/showpage{}N/erasepage{}N /setpagedevice{pop}N/copypage{}N newpath}N/@endspecial{count ocount sub{ pop}repeat countdictstack dcount sub{end}repeat grestore SpecialSave restore end}N/@defspecial{SDict begin}N/@fedspecial{end}B/li{lineto}B /rl{rlineto}B/rc{rcurveto}B/np{/SaveX currentpoint/SaveY X N 1 setlinecap newpath}N/st{stroke SaveX SaveY moveto}N/fil{fill SaveX SaveY moveto}N/ellipse{/endangle X/startangle X/yrad X/xrad X/savematrix matrix currentmatrix N TR xrad yrad scale 0 0 1 startangle endangle arc savematrix setmatrix}N end %%EndProcSet %%BeginFont: CMMI7 %!PS-AdobeFont-1.1: CMMI7 1.100 %%CreationDate: 1996 Jul 23 07:53:53 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.100) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMMI7) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle -14.04 def /isFixedPitch false def end readonly def /FontName /CMMI7 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 110 /n put readonly def /FontBBox{0 -250 1171 750}readonly def currentdict end currentfile eexec D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE 3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B 532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470 B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B 986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE D919C2DDD26BDC0D99398B9F4D03D77639DF1232A4D6233A9CAF69B151DFD33F C0962EAC6E3EBFB8AD256A3C654EAAF9A50C51BC6FA90B61B60401C235AFAB7B B078D20B4B8A6D7F0300CF694E6956FF9C29C84FCC5C9E8890AA56B1BC60E868 DA8488AC4435E6B5CE34EA88E904D5C978514D7E476BF8971D419363125D4811 4D886EDDDCDDA8A6B0FDA5CF0603EA9FA5D4393BEBB26E1AB11C2D74FFA6FEE3 FAFBC6F05B801C1C3276B11080F5023902B56593F3F6B1F37997038F36B9E3AB 76C2E97E1F492D27A8E99F3E947A47166D0D0D063E4E6A9B535DC9F1BED129C5 123775D5D68787A58C93009FD5DA55B19511B95168C83429BD2D878207C39770 012318EA7AA39900C97B9D3859E3D0B04750B8390BF1F1BC29DC22BCAD50ECC6 A3C633D0937A59E859E5185AF9F56704708D5F1C50F78F43DFAC43C4E7DC9413 44CEFE43279AFD3C167C942889A352F2FF806C2FF8B3EB4908D50778AA58CFFC 4D1B14597A06A994ED8414BBE8B26E74D49F6CF54176B7297CDA112A69518050 01337CBA5478EB984CDD22020DAED9CA8311C33FBCC84177F5CE870E709FC608 D28B3A7208EFF72988C136142CE79B4E9C7B3FE588E9824ABC6F04D141E589B3 914A73A42801305439862414F893D5B6C327A7EE2730DEDE6A1597B09C258F05 261BC634F64C9F8477CD51634BA648FC70F659C90DC042C0D6B68CD1DF36D615 24F362B85A58D65A8E6DFD583EF9A79A428F2390A0B5398EEB78F4B5A89D9AD2 A517E0361749554ABD6547072398FFDD863E40501C316F28FDDF8B550FF8D663 9843D0BEA42289F85BD844891DB42EC7C51229D33EE7E83B1290404C799B8E8C 889787CDC194F782420BB447DE705EAE7963391B36647C8B3796E8E8774CD38D 675A89E8D077644F37FBFE9EB36C5B4455A94D61E2EC58C4544B2714F8B66FF5 D09FF25507481406F93BD74C2F14785C9AFFC6458E10A133E0ECD17301B2B5DF DE0C0D73DED3F4BE21027581FC25B49D6B1F1934F8745C4CE9610BE5A10F91C3 561C994E4BCD46A084D51E268092BEA0AB544F91C9CA2692A02575863E04350D 23051121C2B09186AE02C550040C09905EBFAAB4859901E0D1349E104862C122 65A2855C94549313EA44C9D9F1B3EB99D644FA8FE08D5F40A506639B0344B894 882ED4C0BBCFE4A30B6DA93BE0DCA9671E984F279295B45C8DED7D77BA7874AE 8B21F1148B253610333230100049EEBB1D4D58E17059C374AC2AF9CEE11B4D59 A7281AB04644DE042145245F04DE6CB5413889575CD415C721A7C18B3C3FE177 2FD7256E2E686938E36AC765FAF48D83C561C2E25807CDA6087E4A3B1E82216B A3609E28E6B58E3F36CB36315314A72CC7EC4ED8CF2E6761EC6409A74339CAF5 D148FFFAF620CE77 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMMI10 %!PS-AdobeFont-1.1: CMMI10 1.100 %%CreationDate: 1996 Jul 23 07:53:57 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.100) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMMI10) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle -14.04 def /isFixedPitch false def end readonly def /FontName /CMMI10 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 21 /lambda put dup 22 /mu put dup 23 /nu put dup 26 /rho put dup 32 /psi put dup 70 /F put dup 120 /x put readonly def /FontBBox{-32 -250 1048 750}readonly def currentdict end currentfile eexec D9D66F633B846A97B686A97E45A3D0AA0529731C99A784CCBE85B4993B2EEBDE 3B12D472B7CF54651EF21185116A69AB1096ED4BAD2F646635E019B6417CC77B 532F85D811C70D1429A19A5307EF63EB5C5E02C89FC6C20F6D9D89E7D91FE470 B72BEFDA23F5DF76BE05AF4CE93137A219ED8A04A9D7D6FDF37E6B7FCDE0D90B 986423E5960A5D9FBB4C956556E8DF90CBFAEC476FA36FD9A5C8175C9AF513FE D919C2DDD26BDC0D99398B9F4D03D5993DFC0930297866E1CD0A319B6B1FD958 9E394A533A081C36D456A09920001A3D2199583EB9B84B4DEE08E3D12939E321 990CD249827D9648574955F61BAAA11263A91B6C3D47A5190165B0C25ABF6D3E 6EC187E4B05182126BB0D0323D943170B795255260F9FD25F2248D04F45DFBFB DEF7FF8B19BFEF637B210018AE02572B389B3F76282BEB29CC301905D388C721 59616893E774413F48DE0B408BC66DCE3FE17CB9F84D205839D58014D6A88823 D9320AE93AF96D97A02C4D5A2BB2B8C7925C4578003959C46E3CE1A2F0EAC4BF 8B9B325E46435BDE60BC54D72BC8ACB5C0A34413AC87045DC7B84646A324B808 6FD8E34217213E131C3B1510415CE45420688ED9C1D27890EC68BD7C1235FAF9 1DAB3A369DD2FC3BE5CF9655C7B7EDA7361D7E05E5831B6B8E2EEC542A7B38EE 03BE4BAC6079D038ACB3C7C916279764547C2D51976BABA94BA9866D79F13909 95AA39B0F03103A07CBDF441B8C5669F729020AF284B7FF52A29C6255FCAACF1 74109050FBA2602E72593FBCBFC26E726EE4AEF97B7632BC4F5F353B5C67FED2 3EA752A4A57B8F7FEFF1D7341D895F0A3A0BE1D8E3391970457A967EFF84F6D8 47750B1145B8CC5BD96EE7AA99DDC9E06939E383BDA41175233D58AD263EBF19 AFC0E2F840512D321166547B306C592B8A01E1FA2564B9A26DAC14256414E4C8 42616728D918C74D13C349F4186EC7B9708B86467425A6FDB3A396562F7EE4D8 40B43621744CF8A23A6E532649B66C2A0002DD04F8F39618E4F572819DD34837 B5A08E643FDCA1505AF6A1FA3DDFD1FA758013CAED8ACDDBBB334D664DFF5B53 956017667C419C4021DA92976C7550A196C257FC2124FAD5E653AFE71A185EEB 32D003E13145A2B8230CFA65B8B8C55DD032F84307FE53FDB700A58C7546787D F306D3D7E14C9D301B79DD47D3141BACD987E3690D86AA69CF7722AE378E8106 F3B49F218B58AB401B1788AED031850B2079110EA4525D966384CF6A866894D5 FCE658FEDD8BB4F5AF7DC0C604BCCD85B7B4DD35403C23FE5ADC9EB8DAEC97F9 13E08ACDB69680FEAC82AC424C125AD328E3855A52124AAF3C324D93EBE9D9AD 1AE1B26E8C743773A084881C44536F54945D8168D8E40C4CA01914744E49FAE6 A27ABF29EA34543B8DEEB025DCD05DBC3BCB8C107836E2E97F863E543FC13BB9 481424298C5AB72CC44DAE649D4A16224352E91DA24A564DB9370A34155495EF 0EB287BE20162E9DB950508E4FB8C5CFE5B6A062D3016E2E1A15E03F915C8025 5843D5316A69BA43C57AA2A13991ED11D6931378A73F95FE3797BA7977E0FADF F95AF97E568E59CCEF1036DE58BA2D7629F058E39CA08E94B2B08D202603F2A2 63E01E2A74F2D18DFAE6DC8BFA435CA36E98EE1F6E5B92D449AFBCF623404F16 06B5D0E252F57A667A7E17600492A31A1BC8A03ABCE2F8FB82F38728550FD88E DEA92F6BD0B42BD28704228DD83DF9CBC64511CEECEDF681E689DC9C5B141741 0244E24785B7B13C298F7184F0F386105DD3FCD7AF22F27AEE2DFBA7185C6A26 7C108B92357FE952CFDBCB02F45959E3D0F730E75E8A2867DD9D4FCA3987FDC4 C062FFD0B4525D1E45261282D83CE455AF1EA5098E5BA1F4053EDA544D1B3045 74E741AC7D61C398361958DFF4E3F89160A6FC6E4073DA3D98E8260B1F83952E C7AE56387BF58B0956CBCFDD0BCE334E9A2AC8EDA303679218B2192B28CA3A54 6E07FFFB11FEB487F472F3BA46D45FB57E2875F40994041BCB961E08D3DD9C26 98DD85308B7C1059B032D56DFDC2EDA51ACF55F6050BF6A6C85A4AD188B68C1B 5C69B21A58076CF11C4D54E4A0FB814E7B0AF87AC3D7DD4FC210997C639E6EA7 30B3D4D98343685C5022835F83BB3723BF9EDB784B9C27B3E061F80CA99F2ED7 BFAA1514BEDAF44D7739747033811C07E6F26F74EDC3F52CA75AC4CB45D98D65 DF1D012F72033A5426C6346003C27A70B937D5CD9124FA6C8BFCC506C6043319 7F97A41A0E56D28DDEC3DFE291378A182CC97CEFFC995544B4789BC55712FD70 CDA866003EF8BC18E5D768F0F28E24C4DC790DF7BC60688C2C034A80031789E9 BDF8293E12533F0D027CFC6BD9ACD7FD8DC3113D7E69430F31A2D2141306EC6D C40898CDCF1FEA68BBEE05A44899317003EAF3B392D21DA573792C658F6197B2 9A9AF98D38F447ED02155258DA18568C5D8A8DF457539C071F5C441B46B6880B 95D16DD7AD26B90992996E17C2518AEEEC158794B33D9C67BD42D3A2769FD0B0 38BA341767B4A776094DAA95CAE2E22206167901F4CF9C1F1D12E4F4FE2CF1E5 73EFF0D3B67ED7C2BA3D48D22E185B2D49BFF2B9317FAEEA390A56874C56281A AA894B305C8F4EC9C068B687DC999928815C9B6A15E286734E36C810FF7F28F2 7EF1CE4F0D8E9E2DEDDBCDD6ED9B23B26E84D397277D2E1AE6D5941D5837DD63 D852964583EB15AD46B8003E587AE79C46A0B6CFFEF307CA0737DE04707C94D1 5C1AA6D885D1AB3A3D289CA8D67F250A2B4B56CF0FE10D0AC8C78D5D85AFD3CA 97353AFB3750E645E7BE25957720365488B7E24F51F38DE612EEC02DB6A77B77 A51DDC9A4A3ADB8C4013638FD29C1320E6A8689AF95891A648EF1411E5C00A64 9F86FBDDD8771832F0FF485D9C1EE01C18F362E45716D38CE66648E8164C1579 BE0CBFD457660E803AE6437B0F73A4FCDD1D27671FC3187E8FB62CAA700BCFEE 3CF4D2B21AEB2783366A43C7139DD1962B082CAC832939CD5B3A59897E932C66 82BADB43A097341294BEC25F3A49D4AE220167B1E9592131748ADFB765D417B9 9497BC86C8371BFDB710BB5C0BF8F420A29E8227E58CBE5D639299F0960C3CD0 4EB3D7B804A687F005773EFAE75DA459F27DB446CFEB5F5B809EB5736F05828A 0B8F45D88551DBA6A6EE56AC0B6BCC03E804ED78CBD811D84D59ACA5A4A48187 6FD975A3311F2693C7460AFE73C20B8C83887835F06D664FD3D796BD64E4C822 545FBCA53D881EA8989B963808F984A4C7DB63A430EE68142228E86821290ED7 508EC2EB07929B488E718188CBA54E14C6525209 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont %%BeginFont: CMR10 %!PS-AdobeFont-1.1: CMR10 1.00B %%CreationDate: 1992 Feb 19 19:54:52 % Copyright (C) 1997 American Mathematical Society. All Rights Reserved. 11 dict begin /FontInfo 7 dict dup begin /version (1.00B) readonly def /Notice (Copyright (C) 1997 American Mathematical Society. All Rights Reserved) readonly def /FullName (CMR10) readonly def /FamilyName (Computer Modern) readonly def /Weight (Medium) readonly def /ItalicAngle 0 def /isFixedPitch false def end readonly def /FontName /CMR10 def /PaintType 0 def /FontType 1 def /FontMatrix [0.001 0 0 0.001 0 0] readonly def /Encoding 256 array 0 1 255 {1 index exch /.notdef put} for dup 11 /ff put dup 80 /P put dup 83 /S put dup 97 /a put dup 99 /c put dup 100 /d put dup 101 /e put dup 102 /f put dup 103 /g put dup 105 /i put dup 108 /l put dup 109 /m put dup 110 /n put dup 111 /o put dup 112 /p put dup 114 /r put dup 115 /s put dup 116 /t put readonly def /FontBBox{-251 -250 1009 969}readonly def currentdict end currentfile eexec D9D66F633B846A97B686A97E45A3D0AA052A014267B7904EB3C0D3BD0B83D891 016CA6CA4B712ADEB258FAAB9A130EE605E61F77FC1B738ABC7C51CD46EF8171 9098D5FEE67660E69A7AB91B58F29A4D79E57022F783EB0FBBB6D4F4EC35014F D2DECBA99459A4C59DF0C6EBA150284454E707DC2100C15B76B4C19B84363758 469A6C558785B226332152109871A9883487DD7710949204DDCF837E6A8708B8 2BDBF16FBC7512FAA308A093FE5CF7158F1163BC1F3352E22A1452E73FECA8A4 87100FB1FFC4C8AF409B2067537220E605DA0852CA49839E1386AF9D7A1A455F D1F017CE45884D76EF2CB9BC5821FD25365DDEA6E45F332B5F68A44AD8A530F0 92A36FAC8D27F9087AFEEA2096F839A2BC4B937F24E080EF7C0F9374A18D565C 295A05210DB96A23175AC59A9BD0147A310EF49C551A417E0A22703F94FF7B75 409A5D417DA6730A69E310FA6A4229FC7E4F620B0FC4C63C50E99E179EB51E4C 4BC45217722F1E8E40F1E1428E792EAFE05C5A50D38C52114DFCD24D54027CBF 2512DD116F0463DE4052A7AD53B641A27E81E481947884CE35661B49153FA19E 0A2A860C7B61558671303DE6AE06A80E4E450E17067676E6BBB42A9A24ACBC3E B0CA7B7A3BFEA84FED39CCFB6D545BB2BCC49E5E16976407AB9D94556CD4F008 24EF579B6800B6DC3AAF840B3FC6822872368E3B4274DD06CA36AF8F6346C11B 43C772CC242F3B212C4BD7018D71A1A74C9A94ED0093A5FB6557F4E0751047AF D72098ECA301B8AE68110F983796E581F106144951DF5B750432A230FDA3B575 5A38B5E7972AABC12306A01A99FCF8189D71B8DBF49550BAEA9CF1B97CBFC7CC 96498ECC938B1A1710B670657DE923A659DB8757147B140A48067328E7E3F9C3 7D1888B284904301450CE0BC15EEEA00E48CCD6388F3FC3BEE09555C11E6E295 71B219B380EE9E5BB17AD84B4E8AED35880BD88E5AC7D9FE25C46889CD093396 F0E34A62F93E64C8E7975CFD617121244AB09FF9A4F73F8166197D0CDE2EEBB3 81AB9BD8329579C2122368F56DEB89BA6E42C5D9E20F2789CC4A89E4AD9B877F 8A0ACB84936F109D86211169257C19756A97E682601F4D1E7ED950A351C14DAC 4BEA7FB0E58FB5AEB55BC09B1253748B61B4E00C448F263458BF958D3986BF18 9636037E95FB425AAC96FCED5B4C766F93041FAA0DBB196B0A220B8E3A9FCA6E B4F5C0C775C25AFF4F5099CD3A2FA59ACA735718F8E90B351B015320794A89E8 4C34F32B465E201008CCC0A15C2DEE572BDA14D8BDDFCF2743A15F8A93386861 828F6251F206B9131C951D1ED4364A9CCE507E2959A1DA04A777B592888D38ED E68FFB3EFE83870BA8E04B88C9EEEB2DB80D4D07B52CE914D9DADF825A5301AC C64063909D6C1DC84C274C90004F41A1FAFD450805C5DD2A8E4F4C23E114246F C103EB63B58F33E44DD04F6367E04C3CBB3400BA3C1943B874CFB7DBF6A3EB5A 3F665C5A98F578A03948821E40D1608FB70C5915CA0DE369A0D7112BFF6CAE56 CB9BF699DAF3859F2B46DF97AE05915E791F1CE849154C53C4403EFD6F1A44EF 78C167190F3326BA35B2A0F95CD03492DBA2903489ABB6B2EB9F977F3F4D690B 31E8F6E32F83D91F721ABD116A40698F26610853E7FD075478979BEF42166C1B 312E8C20CB3F080B08A69416DA402D336C627BABC4737FC72F8F4F6BB7D73551 EE33D3CEA9052546399CE5FF4996968D1EF09B7C19995C083E727D2398021CAE 6B824B074160730AE1D61010FB6167E8AC42145BCE800A58D221004F6B953F48 B4A99CBF85F829F34F76B02D02D956F2D9710B38FE827FE961A3BA3E78F64ECD DADF68975D97F94EA8A698A5C6C48DFFF960EE628E8515535F59220FCB5E7EBA 98EFC03380413965B0498C169ECE75E7981C6BFBD64D544B919570F297C004CE 0C3B1A7E5D3C322887DDB7AA315551E09616F5D1E4FF1E7506494F362B124790 B10F52C94E6609CB9ADAEFE74528C271FCA5710E67DB9A31A4EE5E8B068DC248 F98C0675DCF2EC93227746654ED73ED27B057EDD4280D406B7201ACE79B44665 3B433E622C7260EC370B378BA1B72470FD7A76128EF6906B32D2B9FB28B1B955 6C528D23962F76D5E96E6D46864CCE7F859C7FC333EE98134E1C275D017B3EC5 E6ACB222D33909711D32D380BCFE49B06461B8B9D06A47C601860487F717AA6C EA7C03055A933CAA161CE580F3450B0BDBA1789FBF48822B33BFC5FAD73A5F02 7EDF4AFB79B876CA70C352F1711466C1C680D7B512B75A5719B5C85CF6F2FB9A 6F974915BA9F3DBB83596C2A63EC5D2AF5209E601909E3FD7466D32533A8D4CD 69B5619E01C6F9F2C6E16AA685CBB41EF8C185095565C48E21AF24A1018AD349 63A4B5CF7F80881B6D35808FFA6C1451E5168F7BBE77E25C3A1C2E407EFAFDBB 4F917C49D468A22DDECEC9A3A1FF3D279BB3D9BC351FAAC787C547EB9DB5B49D 0E6E89F4156AD627997804ECD5547A106EFC52EA95952F3B2F3653648E14B6A2 0EFE133E059B49EF76D8B0B9A6734B160AA3D4EE66DCEE0CCF3A559A1F5B9A17 BEFFE89C9AC2EA49668C017472AEFA0143072B9762D554AF4AE52A703DDE0F42 8E156F823103EDB2D0B475415FCBF7E031B8363C9C318D396D77100C0F05DE27 A57F813EC8FC949A6409A837245C5AE75F47120F9ABF8A144B7194615983703C 8530C9A661EEC72E94D525C176FB0CB2E753316267FB9628C583FB1E8A917929 BE657AE4CAD788A304D20E3B8BE0B8AB2D43BDA040B2ADF4B52C9D7AEC628D61 29CCE50223F113D55423532EAFE56F39264A3FE995DCF052DB9A5B81D518C916 4CFC640AD12970EEF33C45A8FE6F12D0A65B5C31D31B9626F4D9128494DB3198 C2F6B35AAF020C4FE30946D4DC525DC3C8C99BB3D99B5BA0F1C30E28651C635F 3630C72C015B53B0AD16BCE319499FFEA5CA909497591B58EB970719C9B9ECCA 190D4B57DFD7FB841247C96750840D8E38B4D15D13BF0A1695015C0942B9B6C8 9780AAE344387B2B303F54C4CC0A03739531DB46E00C408CD0081FA59047DF2C 884EA1704F9A131C580B7F9F7005974794F9F0D67E5D99156DD610B5B5E99111 EBFFE160EAFB50D998220BD0436A6EB83787F8DBDD0453195BA81597051FFFC5 15190CE23F15CD662B3C55BC6F6080C3E8CCDACD951173A36C9EEDDEA0DDAD59 9591AE0FE218A738BEFE329C4FEFA47B402A2A36ED0204CD49C25C4D9C614F2F 7BFCA7780AA6EDE2748AD6D7F44D38D94B5261F55C482CEE244542BFF2E0C33C A7C5E36BFF9B970A99C766B423F84A7220A882B03A55389E008196EB1CE9C217 7CE9908868E87C2E249BA31169FABBC8DBE26275AB3604499B9E636C2E0EB879 BAEF7336259124FE3BFF7722D0014ED7FBDDAB47E102B0C252C1AE5048C75A0A 9E833BA3A779D8EE03050402C2FD34249E6129536DC5BCEF2FB6F6A121593799 37D5027D95A75B42C380C9F236E2F98D7F4DB8ACFFEE09DFA0A107DC4A6FB537 9EA4229F0BC07695D1472A1C0FAD646CBCB92C4A76EFA91DA6725EBACB3FB9B5 FC788E53EB917A2FC558AF7F53AF3CED7EAD84B0B997ADD1585CBD2E9E41B87D 6097F74D8F06A18302A349B92AB855888C0ECFCD9CB1A1440BBE58C4EF9160D0 0B78AF901A8ADAD550ECE4F393AA07D85F786090BC217FC59744577996EE8571 9E4820752F8EAC0CB795047DD76A4CBDBBDDB48350FAF52323FB172E6FEED926 A361B77ABFA6EFB73851F9F802CCEB2798746B2EC8B43FB801E0553D034A0132 3905BA38C3124DC5E0E9C51045015817AD5FC750924158CEF440054FADB0FC02 C3E330F90CD86847AA59C94F5EA4626E10AF33CBADC593764BFE51E712968F6C B63B997B6A4FB61F8F6220E18735647506FA4A0AD227A69DCE4AB979753BEA1A A3590F7BFC682D1E2509995E5F567549E36FE6675C47749AAD14CB2112854FE6 59FE56D9C4DFC06B21B6F7DD421CAE134A29A061DCD4490F81F71D0780BDE07B 0920F2543D775054BCA2BF888CBD0B08E6CF8B099BBBD91146C4577959FEB436 3413979503B3562A50278E6B43A87AC37C2B68A351DBC54936B9152B7D56A526 691F507C42E94024409306790E89070C4D0CA5FD98018BF2CD734D30AD2D2AE5 50E9580F7B3A028C1F260D5A60F03EFEA40DA432FE47125AD29DD6778F58F0EF B37DE5C14DDF2789585D1FC076490EB83C4B864849C42BEBF86BA27C9BAC2F23 ABC7D954A13F5FB724E4B2189FEC5F4650EEA7A797E8B031C5CC8AC1C5819185 3595BA9A366AE3569DC8C95164978DE77FAD5F770CD87A121A2BAAD175AE1547 60930A498AC81BAB2BB25F4CC1C300823ECAD33FC04EC1A4A665BCE6C0420DD6 2F1A030DA0B1AFF0DD3443EC28BD6E47524FFFC53A40757609505802BCE97D01 30F10E38C726D5554EE81B8C47F78DB35C282ED1696DDD300531AF4E11F8926C 2EFF8FA61826ACC189B2902AEB87CB48D352B4B10423FD06A91FB953672CA8D3 D4C517E3ED112B41434F715364CFDE6C849CC26CA8AD724E28EDF71DA21EC234 B9641433564CD8F816630AC04EA580B5DBF4B0BD56E69D65293E8DAFFE140911 65003FF43DB40A9AFE05690FD3BC6CD7C997DFB450DBFD29734D4856711934C9 EFA0C0EF473BE66B036A32D5F10B589ACE6FBBA0D0574DE6539DE1A4E62E1C3E E2507D3B7F6D8ED3169CE5461B9C1EFCE26FF600D8B46836DF30FF74D0524A88 D6BDD9D996B4D3963DBC949551933A87A872BE6CE51184DF5657ECF24367EB14 A7814BEDDC85137F40B1A8F7245584DAA752B0C26BD1B160DD331FB94B2027EA D470CB8705F1BCF75375E46CA5E8C105A5483DDB620D225D916B496058A1B307 9120D9199CE413BE4941364C0F3ADA50AE291A517B3F95D67761BE18033554AB 1351A1F87DE1989437A2F775A894EEEE906DB9F946CE8D0B6EAE3DFB4A79BAF2 AB27DFCF79FB1175F1C0072A663A10CEE197E6B191DAA644A4A0BCFB87EAF4D2 D158EB86B5183EF7608147EFB2F1CB2DCB0051F2AE6585AF4736679ECDE5B502 CD2DEA962727A6994C04AA09C6716BF5B3713BF8DE70875670DA5A1CAA9B2159 ABCDA4503F12060F81B289B6D19708A31A7FA8BDAEB65F1D7543505D26CB3E8A F056FC84FCB45C6895EE4A34BDC1949E7E124F1E1FF63D03970CAE45A26B204B 45EBA6BFDF5E0F11FCF8724AB4B201C6F2768C5AACC6309F2D135D9969C0714E E51DF14121BAC17618A4792F697E1B6C3AD3485F0927FDD53FD0567E56D7A152 DE6A8BFF2A941D6156EFAAAC7170A665CF57A0B9FD242829349F267EAB9C2296 4DB761395FFBD75DE58AB7481A561CEE5372E454D903ECEC26A777B5C4AC5227 C0B6E5FB982C1BD627339C4990FD414588D05A5FAA441A3FB35A3BA363761EAF D4AB19C7874CD87267E59394D0B09CB36F0F9CBF0573E411FCF0ECC81388AB66 7BA3759B86B4DACDE1ECD71A49B76E3BDB415361B2312BB2C72D850BBF35AF4F 8F5BF0A277A7D0FD46DC3054B81DBD44C99E8002A43A0A354B78EDD192FF1E2E 8FC01D71641733D8241EC4E0ABE635C97C8133304F094B5BE9A47F13B7489CF5 42F18F2D72C59DCFE3A4A26331AA8EEBBC26D41CCF34BD10850D6EC8729C2911 55394002DF4820BC2CEBE107AD66C7F1EB1B7B887C06F37A5A2B1979D4BF01B2 4EC9ED746D1D904C58C59F8B783DE3630B44905C93780CD0CE3005D77E2DFA40 3B8DF0E0CDDA7AEDB5E495AF1B9ED2B928BA26A47076AEDC234F3D659CCB0534 02BE5739BC3B73A58C600714CC593D66508A9716EC6338EBD103E0799A168E15 98C3311F473F8FBDF5630F726AEC51265AFEBB6C2412082BAA93504247199BC1 8FF8E99410D87D06F90ABEE08C4E4CB26EB6F9CEEBF42DA2C6778E0A6A7FACCD CC8CE175CCDE5AA28061DA2B2BB6664C9DEB4423F6EF3B2A23F00B9B4F197022 29E4DA035A3BFD78AF62F864CE839EBA53754A3A1589C8E781EC0785E1196AF1 0060D953C6DDED44CFE8ED5340D198941ED0F8D8259FEC912B70FBF47BB19E92 F80B5D829B1AC466776C1182BF76D23CEB0FA832CBE0653E03850C48F9F428AB 16CD80233322C1063127B42E16F395D92132CAE185D7230711171634B4FD4418 7DD4F3CC51046D3CA312EDCC6784C9843E6682E9D9EC3C8EA8C98B5E2626F227 C744E7C1B284EE0B75C913518C312CEC2BF5F9EEB138C6587422BA711462123D 3346589E4D4081EFEC2E86AF9DE6B7B824B91E95A345F3D6DF3E929676E667C6 7644C7ED5B191944C024193614441D7E1428343BD3FE7EA79C206350BABDF3E1 88A73FF53D0F25F0D4BB80AB45C84A5823012456C44366E64E7A8DA88875D92B 33E6C70BB9A1A19B451587608AFCEDBCE78C59739D4D29B4DAD9824C47D86634 2F32D68D2918D023FA6BBA0F2CFDDB7B6A6758D71F2AB38A89F3ABA72F23AA33 AF8AAB4AE56C6A32BEAF8B0A54530721E6D36352988B504A7B8902AFEC0761BB B1C1A154F598A52A0C35D8725FB0EF2750BCCA83980108E91D070124CA4043B3 0938932C9482342BB0713631224289265487E5588D51D0C1A0D5CF9812578DFC 4BBD2FEAEE32EF988716B638D3547870BFC23765295F342416A8BE03F7CF0F41 66C055B94B80DB53E00B705CEA4BF36EBC4F6C61E20A33F2C78DFCF955E45B12 7EB7BC582E6986731F18FA1469C00C05B78C7E5B119EC6E4673B9D874A0B0111 57B5B15EB0285848C2D61C87901517AA22568D2E4C3F40514C7F707B65747D37 00E1D8EB7FA348F9AED575F35C8BBD095658A26D0CF5C45E258F4BAF6D8A9BF1 391AEBB26B938245F37772515EA6BD760B72456657B0DA0AFC49C4D652F7F641 C99AB170CB821BD32A 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 cleartomark %%EndFont TeXDict begin 40258437 52099154 1000 600 600 (/home/kasper/tmp/kt_temp/kt_temp_makefig/makefig.dvi) @start /Fa 145[41 110[{}1 58.1154 /CMMI7 rf /Fb 135[47 49[53 37[54 5[43 2[41 50 48 21[{}7 83.022 /CMMI10 rf /Fc 139[32 33 33 1[46 42 46 69 23 2[23 1[42 25 37 46 37 1[42 13[46 2[57 68[48 11[{}18 83.022 /CMR10 rf end %%EndProlog %%BeginSetup %%Feature: *Resolution 600dpi TeXDict begin end %%EndSetup TeXDict begin 1 0 bop 166 1181 a /PSfrag where{pop(int)[[0(Bl)1 0]](prod)[[1(Bl)1 0]](diff)[[2(Bl)1 0]](psi)[[3(Bl)1 0]](F)[[4(Bl)1 0]](mu)[[5(Bl)1 0]](nu)[[6(Bl)1 0]](rho)[[7(Bl)1 0]](lam)[[8(Bl)1 0]](x)[[9(Bl)1 0]]10 0 -1/Begin PSfrag}{userdict /PSfrag{pop}put}ifelse 166 1181 a @beginspecial 0 @llx 0 @lly 213 @urx 153 @ury 1417 @rhi @setspecial %%BeginDocument: exp1.eps %!PS-Adobe-2.0 EPSF-2.0 %%Title: exp1.fig %%Creator: fig2dev Version 3.2 Patchlevel 5-alpha7 %%CreationDate: Sun Jul 30 23:11:05 2006 %%BoundingBox: 0 0 213 153 %Magnification: 1.0000 %%EndComments /$F2psDict 200 dict def $F2psDict begin $F2psDict /mtrx matrix put /col-1 {0 setgray} bind def /col0 {0.000 0.000 0.000 srgb} bind def /col1 {0.000 0.000 1.000 srgb} bind def /col2 {0.000 1.000 0.000 srgb} bind def /col3 {0.000 1.000 1.000 srgb} bind def /col4 {1.000 0.000 0.000 srgb} bind def /col5 {1.000 0.000 1.000 srgb} bind def /col6 {1.000 1.000 0.000 srgb} bind def /col7 {1.000 1.000 1.000 srgb} bind def /col8 {0.000 0.000 0.560 srgb} bind def /col9 {0.000 0.000 0.690 srgb} bind def /col10 {0.000 0.000 0.820 srgb} bind def /col11 {0.530 0.810 1.000 srgb} bind def /col12 {0.000 0.560 0.000 srgb} bind def /col13 {0.000 0.690 0.000 srgb} bind def /col14 {0.000 0.820 0.000 srgb} bind def /col15 {0.000 0.560 0.560 srgb} bind def /col16 {0.000 0.690 0.690 srgb} bind def /col17 {0.000 0.820 0.820 srgb} bind def /col18 {0.560 0.000 0.000 srgb} bind def /col19 {0.690 0.000 0.000 srgb} bind def /col20 {0.820 0.000 0.000 srgb} bind def /col21 {0.560 0.000 0.560 srgb} bind def /col22 {0.690 0.000 0.690 srgb} bind def /col23 {0.820 0.000 0.820 srgb} bind def /col24 {0.500 0.190 0.000 srgb} bind def /col25 {0.630 0.250 0.000 srgb} bind def /col26 {0.750 0.380 0.000 srgb} bind def /col27 {1.000 0.500 0.500 srgb} bind def /col28 {1.000 0.630 0.630 srgb} bind def /col29 {1.000 0.750 0.750 srgb} bind def /col30 {1.000 0.880 0.880 srgb} bind def /col31 {1.000 0.840 0.000 srgb} bind def end save newpath 0 153 moveto 0 0 lineto 213 0 lineto 213 153 lineto closepath clip newpath -101.1 312.8 translate 1 -1 scale /cp {closepath} bind def /ef {eofill} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth} bind def /tr {translate} bind def /tnt {dup dup currentrgbcolor 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} bind def /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 4 -2 roll mul srgb} bind def /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def /$F2psEnd {$F2psEnteredState restore end} def $F2psBegin 10 setmiterlimit 0 slj 0 slc 0.06299 0.06299 sc % % Fig objects follow % % % here starts figure with depth 50 % Polyline 0 slj 0 slc 7.500 slw n 4410 2790 m 3825 2925 l gs col0 s gr % Polyline n 4410 2790 m 4905 2925 l gs col0 s gr % Polyline n 3690 3240 m 3150 3375 l gs col0 s gr % Polyline n 3690 3240 m 4140 3375 l gs col0 s gr % Polyline n 3015 3645 m 2655 3825 l gs col0 s gr % Polyline n 3015 3645 m 3465 3825 l gs col0 s gr % Polyline n 2610 4140 m 3015 4275 l gs col0 s gr % Polyline n 2115 4590 m 2115 4770 l gs col0 s gr % Polyline n 2115 4590 m 1755 4770 l gs col0 s gr % Polyline n 2115 4590 m 2520 4770 l gs col0 s gr % Polyline n 3015 4590 m 3015 4770 l gs col0 s gr % Polyline n 4095 3690 m 4095 3870 l gs col0 s gr % Polyline n 2610 4140 m 2160 4275 l gs col0 s gr /Times-Roman ff 190.50 scf sf 3600 3150 m gs 1 -1 sc (prod) col0 sh gr /Times-Roman ff 190.50 scf sf 4050 3600 m gs 1 -1 sc (psi) col0 sh gr /Times-Roman ff 190.50 scf sf 4860 3150 m gs 1 -1 sc (x) col0 sh gr /Times-Roman ff 190.50 scf sf 2970 3600 m gs 1 -1 sc (diff) col0 sh gr /Times-Roman ff 190.50 scf sf 2070 4500 m gs 1 -1 sc (F) col0 sh gr /Times-Roman ff 190.50 scf sf 1620 4950 m gs 1 -1 sc (mu) col0 sh gr /Times-Roman ff 190.50 scf sf 2070 4950 m gs 1 -1 sc (nu) col0 sh gr /Times-Roman ff 190.50 scf sf 2430 4950 m gs 1 -1 sc (rho) col0 sh gr /Times-Roman ff 190.50 scf sf 2970 4500 m gs 1 -1 sc (psi) col0 sh gr /Times-Roman ff 190.50 scf sf 2430 4050 m gs 1 -1 sc (prod) col0 sh gr /Times-Roman ff 190.50 scf sf 2970 4950 m gs 1 -1 sc (mu) col0 sh gr /Times-Roman ff 190.50 scf sf 4050 4050 m gs 1 -1 sc (nu) col0 sh gr /Times-Roman ff 190.50 scf sf 4320 2700 m gs 1 -1 sc (int) col0 sh gr /Times-Roman ff 190.50 scf sf 3375 4050 m gs 1 -1 sc (lam) col0 sh gr % here ends figure; $F2psEnd rs showpage %%Trailer %EOF %%EndDocument @endspecial 166 1181 a /End PSfrag 166 1181 a 166 94 a /Hide PSfrag 166 94 a -574 152 a Fc(PSfrag)26 b(replacemen)n(ts)p -574 182 741 4 v 166 185 a /Unhide PSfrag 166 185 a 67 284 a { 67 284 a Fc(in)n(t)67 284 y } 0/Place PSfrag 67 284 a -3 368 a { -3 368 a Fc(pro)r(d)-3 368 y } 1/Place PSfrag -3 368 a 48 484 a { 48 484 a Fc(di\013)48 484 y } 2/Place PSfrag 48 484 a 109 567 a { 109 567 a Fb( )109 567 y } 3/Place PSfrag 109 567 a 101 683 a { 101 683 a Fb(F)101 683 y } 4/Place PSfrag 101 683 a 116 766 a { 116 766 a Fb(\026)116 766 y } 5/Place PSfrag 116 766 a 120 882 a { 120 882 a Fb(\027)120 882 y } 6/Place PSfrag 120 882 a 123 966 a { 123 966 a Fb(\032)123 966 y } 7/Place PSfrag 123 966 a 118 1081 a { 118 1081 a Fb(\025)118 1081 y } 8/Place PSfrag 118 1081 a 69 1181 a { 69 1181 a -42 w Fc(d)73 1151 y Fa(n)119 1181 y Fb(x)69 1181 y } 9/Place PSfrag 69 1181 a eop end %%Trailer userdict /end-hook known{end-hook}if %%EOF cadabra-1.39/doc/favicon.ico000066400000000000000000000004761234107666300157300ustar00rootroot00000000000000(( cadabra-1.39/doc/formal.tex000066400000000000000000000034311234107666300156030ustar00rootroot00000000000000 \section{Version 2 notes} \subsection{Structure of expressions} To note: \begin{itemize} \item For a variety of reasons it is make precise when a node is ``a term in a sum'' or ``a factor in a product''; the reason being that a node being zero only influences a single term in a sum but it influences all factors in a product. \item Related to the above: many structure-probing functions currently use ``parent'' without taking proper care of the fact that the parent may be a wrapping ``Accent'' or ``Derivative''. \item This is captured by ``term-like'' and ``factor-like''. The main complication here is to make precise how far up we should go in the tree. Probably just one step. ``Accent'' nodes should handle their zero coefficients themselves, not rely on their child nodes to do it. Single terms in an expression (e.g.~an expression which is just ``A'') should also classify as term-like. \end{itemize} \subsection{Localisation of algorithms} \begin{itemize} \item Many algorithms be in a situation in which the called node is a sum which ends up having zero or one terms. The logic of propagating this should always be: you can touch everything at or below the node, but you cannot remove the node, only set its coefficient to zero. \item However, whether or not a node becomes zero may be a function of the parent node (example: varying a term should keep it intact if the parent is a product-like node, but should remove it if it is a sum-like node. See above. \item All algorithms should always return a consistent tree. Therefore, it is for instance not allowed to return with the iterator pointing to a sum node with zero coefficients (sum node with non-unit multiplier error), the algorithm has to change this to something valid. \end{itemize} cadabra-1.39/doc/general.tex000066400000000000000000000024751234107666300157470ustar00rootroot00000000000000\bigskip {\bfseries Context-sensitive help} Press the help button or the F1 key when the cursor is over a property or command in order to show related help. {\bfseries General help} A paper introducing Cadabra to high-energy physicists is available as \begin{center} \begin{minipage}{.95\textwidth} ``\emph{Introducing Cadabra: a symbolic computer algebra system for\\ field theory problems}'',\\ Kasper Peeters, preprint SPIN-06/46, ITP-UU-06/56, {\tt hep-th/0701238}. \end{minipage} \end{center} \medskip Furthermore, a short paper describing the motivation and key technical aspects of cadabra is available as \begin{center} \begin{minipage}{.95\textwidth} ``\emph{A field-theory motivated approach to symbolic computer algebra}'',\\ Kasper Peeters,\\ \emph{Comp.~Phys.~Comm.}~{\bf 176} (2007) 550-558 (title changed in print),\\ {\tt cs.CS/0608005}.\\ \end{minipage} \end{center} Both papers can be obtained from the cadabra web site or the arXiv. \bigskip {\bfseries Sample notebooks} You may also want to consult the sample notebooks, available from the cadabra web site \begin{center} \verb|http://www.aei.mpg.de/~peekas/cadabra| \end{center} \bigskip {\bfseries Email support} For questions, suggestions, bug reports and all other feedback, please do not hesitate to email the author at \verb|kasper.peeters@aei.mpg.de|. cadabra-1.39/doc/index.html000066400000000000000000000311751234107666300156040ustar00rootroot00000000000000 Cadabra

Cadabra

A field-theory motivated approach to symbolic computer algebra

Copyright © 2001-2006 Kasper Peeters

Overview

Cadabra is a computer algebra system (CAS) for the manipulation of tensorial expressions. It is aimed at, though not necessarily restricted to, theoretical high-energy physicists. Because of its target audience, the program's interface, storage system and underlying philosophy differ substantially from other computer algebra systems. Its main characteristics are:

  • Usage of a TeX-like notation, which eliminates many errors in transcribing problems from paper to computer and back.
  • Built-in understanding of dummy indices and dummy symbols, including their automatic relabelling when necessary. Powerful algorithms for canonicalisation of objects with index symmetries, both mono-term and multi-term.
  • A typing system through properties, but freedom to dispense with this system entirely when it is not needed.
  • A new way to deal with products of non-commuting objects, enabling a notation which is identical to standard physicist's notation (i.e. no need for special non-commuting product operators).
  • A flexible optional undo system. Interactive calculations can be undone to arbitrary level without requiring a full re-evaluation of the entire calculation.
  • A simple and documented way to add new algorithms in the form of C++ modules, which directly operate on the internal expression tree.

Cadabra has been under development for some time now, but has never left my own computer. The current version is the first public release, intended to collect feedback from a wider audience. So, feel free to mail me at kasper.peeters (at) aei.mpg.de with suggestions or constructive criticism.

License and acknowledgements

If you use cadabra or even just play with it, I would like to hear about it. Please drop me an email so that I can get an idea of who is interested in this program.

Cadabra is available under the conditions of the GNU General Public License. If you use cadabra in your own work, please cite the paper mentioned below (to keep the bean counters happy).

Cadabra contains code taken from José Martin-Garcia's xPerm in order to canonicalise tensor expressions. Some of the algorithms rely on the LiE software by Marc van Leeuwen, Arjeh Cohen and Bert Lisser.

Screenshots

Cadabra comes with its own graphical frontend, which is based on the gtk toolkit (or rather its C++ wrapper gtkmm) and uses LaTeX to typeset expressions. This is a screenshot:

native gui

There is also a TeXmacs frontend, displayed in the screenshots below. The associated TeXmacs files can be found in the "texmacs" subdirectory of the source tarball.

screenshot 1  screenshot 2

Install a binary

(note: there are no binaries or packages yet for the new graphical frontend)

First check below whether there is a package for your system, which is always the easiest installation method.

If you are running Linux (on an Intel processor) or Mac OS X, the next simplest way to install cadabra is to install a statically linked binary. You need to download two programs,

Linux, i386Mac OS X, PPC
prompt.gz prompt.gz
CDBRELEASE.gz CDBRELEASE.gz

gunzip them both and make them executable with "chmod u+x prompt cadabra". Put them somewhere in your path. Then the command "prompt cadabra" should start the program (or ./prompt ./cadabra if the current directory is not in your path); if not, email me.

If you want to use the TeXmacs frontend, you will also need the following file:

Store this file in the directory ~/.TeXmacs/plugins/cadabra/progs/ and restart TeXmacs.

Alternatively you can try to locate the TeXmacs/plugins directory on your filesystem (it is usually something like /usr/share/TeXmacs/plugins), and make a (nested) subdirectory cadabra/progs below that. Then copy the init-cadabra.scm file to this directory and (re)start TeXmacs.

Install using Debian, Red Hat, MacPorts, ...

Thanks to Greg Wright, cadabra is available for Mac OS X users through MacPorts. Simply type sudo port install cadabra and all required software will be installed automatically. For questions about this port, please contact gwright (at) macports.org.

Debian and RPM packages will follow in the near future.

Install from source

Installing from source should be no harder than with any other well-behaved GNU tools, i.e. it should be as simple as configure/make/make install. However, you will need to have some additional libraries and tools installed before you can compile cadabra itself. In particular,

  • tcl8.4 with libexpect
  • (on Debian, apt-get install tcl8.4 expect-dev)
  • gmp (configured with --enable-cxx)
  • (on Debian, apt-get install libgmp3-dev libgmpxx3)
  • pcre with C++ wrapper enabled (on Debian, apt-get install libpcre3-dev lib)
  • LiE
  • (no Debian package available)

In order to compile the graphical front-end (add the --enable-gui flag to configure) you also need

  • gtk+
  • gtkmm
  • pangomm
  • dvipng
  • LaTeX
  • the breqn package for LaTeX

Cadabra's configure script will look for these libraries and programs, and tell you when you need to install them. Consult the documentation of these programs/libraries for installation instructions.

You then need to compile and install my modglue library, which is used to connect the various pieces of cadabra together. Download this version here, since it's tuned to cadabra:

This should be a matter of configure/make/make install. Finally, compile and install cadabra itself,

Again, this should be a matter of configure/make/make install. If compilation succeeds, you can also try "make test" for some self-tests (which should all pass).

Since this is the first public release, chances are that some people will encounter problems at one of these steps. Please mail me if you need help.

Documentation

There are currently two documents about cadabra. One is a paper explaining the motivation for writing this software, as well as sketching the internal structure:

Kasper Peeters

The second document is the reference guide and tutorial, available only from here, and still incomplete,

Kasper Peeters
preprint AEI-2006-038

Finally, if you are interested in the internals of the program, there is some doxygen documentation, though this is still in a rather preliminary stage.

For a history of the changes made since the first release, consult the ChangeLog.

Mailing list

There is a mailing list for discussions about cadabra and announcements of new versions (hosted by HEPforge). To subscribe, send an email to

majordomo@cedar.ac.uk

with a body containing the line

subscribe cadabra-discuss

You will receive a confirmation email to which you have to reply, quoting the given authentication key, in order to get subscribed.

There is also an archive of the mailing list available.

cadabra-1.39/doc/maxima_frontend000066400000000000000000000001001234107666300166650ustar00rootroot00000000000000::PostDefaultRules( @@maxima(%) ). integrate(sin(x)cos(x), x); cadabra-1.39/doc/newtree.html000066400000000000000000000261471234107666300161510ustar00rootroot00000000000000 tree.hh: an STL-like C++ tree class

Overview

The tree.hh library for C++ provides an STL-like container class for n-ary trees, templated over the data stored at the nodes. Various types of iterators are provided (post-order, pre-order, and others). Where possible the access methods are compatible with the STL or alternative algorithms are available. The library is available under the terms of the GNU General Public License.
Documentation is available in the form of a postscript and a pdf file (also available in the tarball as a LaTeX file). This documentation is still a bit short and not entirely complete. See the test program (included in the distribution) for an example of how to use tree.hh. Also look at the simple example below. There is also some doxygen generated documentation.
The tree.hh code is available under the terms of the GNU General Public License. If you use tree.hh, please satisfy my curiosity and write me a small email with a bit of explanation of your software and the role of my tree class in it.
The tree.hh library is meant for generic n-ary trees. If you are only interested in AVL binary search trees (Adelson,Velskii & Landis), you may want to have a look at the C++ AVL tree template page.

Download

Everything (the header file, examples, documentation and all other things referred to on this page) is contained in the tarball
tree-VERSION.tar.gz
Feel free to copy the header tree.hh (which is all you need code-wise) into your own source directory as long as you respect the license (see above). The list of changes can be found in the ChangeLog.
See the intro above for links to the documentation. There is a very simple demonstration program available, tree_example.cc (also included in the tarball), which is discussed below. There is also a small test program, test_tree.cc, which makes use of the tree_util.hh utility functions by Linda Buisman; the output should be exactly identical to the test_tree.output file.
The current version works with GNU gcc 3.x and higher, Borland C++ builder and Microsoft Visual C++ 7.1 and higher. It is compatible with STLport.
Tony Cook has provided a version for the buggy Microsoft Visual C++ compilers up to version 7.0. You will have to use a special version of the header file, tree_msvc.hh (currently based on the original tree.hh version MSVC). The difference is that all members of the iterator and sibling_iterator subclasses have been moved inside the class definitions. If you get unresolved symbols in the linking phase, or other weird compiler errors, you should use this header. Microsoft users are urged to upgrade to version 7.1 which works with tree.hh out of the box.

Mailing list and update announcements

There is no mailing list, but I can send you an email whenever a new version of tree.hh becomes available. Just send me an email at kasper.peeters (at) aei.mpg.de and ask me to put you on the distribution list.
I also announce major updates on Freshmeat though not as often as by email.

Projects using tree.hh

The tree.hh library is used in various projects:
Cadabra
A field-theory motivated approach to symbolic computer algebra.
EChem++
A project realizing the idea of a Problem Solving Environment (PSE) in the field of computational electrochemistry. Computer controlled experimental measurements, numerical simulation and analysis of electrochemical processes will be combined under a common user interface.
LZCS
A semistructured document transformation tool. LZCS compresses structured documents taking advantage of the redundant information that can appear in the structure. The main idea is that frequently repeated subtrees may exist and these can be replaced by a backward reference to their first occurance. See the accompanying paper for more details.
libOFX
A parser and an API designed to allow applications to very easily support OFX command responses, usually provided by financial institutions for statement downloads.
A genetic programming project
See this paper for more information.
FreeLing
The FreeLing package consists of a library providing language analysis services (such as morfological analysis, date recognition, PoS tagging, etc.)
Let me know about your project when you are using tree.hh, so that I can add it to the list.

Simple example

The following program constructs a tree of std::string nodes, puts some content in it and applies the find algorithm to find the node with content "two". It then prints the content of all the children of this node. You can download the source tree_example.cc if you're too lazy to type it in.
#include <algorithm>
#include <string>
#include <iostream>
#include "tree.hh"

using namespace std;

int main(int, char **)
   {
   tree<string> tr;
   tree<string>::iterator top, one, two, loc, banana;

   top=tr.begin();
   one=tr.insert(top, "one");
   two=tr.append_child(one, "two");
   tr.append_child(two, "apple");
   banana=tr.append_child(two, "banana");
   tr.append_child(banana,"cherry");
   tr.append_child(two, "peach");
   tr.append_child(one,"three");

   loc=find(tr.begin(), tr.end(), "two");
   if(loc!=tr.end()) {
      tree<string>::sibling_iterator sib=tr.begin(loc);
      while(sib!=tr.end(loc)) {
         cout << (*sib) << endl;
         ++sib;
         }
      cout << endl;
      tree<string>::iterator sib2=tr.begin(loc);
      tree<string>::iterator end2=tr.end(loc);
      while(sib2!=end2) {
         for(int i=0; i<tr.depth(sib2)-2; ++i) 
            cout << " ";
         cout << (*sib2) << endl;
         ++sib2;
         }
      }
   }
The output of this program is
apple
banana
peach

apple
banana
 cherry
peach
Note that this example only has one element at the top of the tree (in this case that is the node containing "one") but it is possible to have an arbitary number of such elements (then the tree is more like a "bush"). Observe the way in which the two types of iterators work. The first block of output, obtained using the sibling_iterator, only displays the children directly below "two". The second block iterates over all children at any depth below "two". In the second output block, the depth member has been used to determine the distance of a given node to the root of the tree.

Data structure

The data structure of the tree class is depicted below (see the documentation for more detailed information). Each node contains a pointer to the first and last child element, and each child contains pointers to its previous and next sibling:
           first_child        first_child 
 root_node-+----------node--+----->-------node
           |           |    |               |   
           |           |    |               V   next_sibling
           |           |    |               |
                       |    |             node
                       |    |               |
                       |    |               V   next_sibling
                       |    | last_child    |
                       |    +----->-------node
                       |                        
                       V next_sibling           
                       |                       
                       |     first_child                  
                      node--+----->-------node
                       |    |               |   
                       |    |               V   next_sibling
                       |    |               |
                       |    +-------------node
                       .
                       .
Iterators come in two types. The normal iterator iterates depth-first over all nodes. The beginning and end of the tree can be obtained by using the begin() and end() members. The other type of iterator only iterates over the nodes at one given depth (ie. over all siblings). One typically uses these iterators to iterate over all children of a node, in which case the [begin,end) range can be obtained by calling begin(iterator) and end(iterator).
Iterators can be converted from one type to the other; this includes the `end' iterators (all intervals are as usual closed at the beginning and open at the end).

Webstats4U - Free web site statistics
Personal homepage website counter $Id: newtree.html,v 1.1 2007/08/21 08:47:14 peekas Exp $ cadabra-1.39/doc/paper.tex000066400000000000000000001220531234107666300154340ustar00rootroot00000000000000\documentclass{elsart} \usepackage{yjsco} \usepackage{amsmath} \usepackage{fancyvrb} \usepackage[numbers,sort&compress]{natbib} \usepackage{hypernat} \usepackage{hyperref} \usepackage{graphicx} \usepackage{xspace} \newcommand{\bs}{$\backslash$} \newcommand{\Cpp}{\leavevmode\rm{\hbox{C\hskip -0.1ex\raise 0.5ex\hbox{\tiny ++}}}\xspace} \setlength{\skip\footins}{18pt plus 4pt minus 2 pt} \makeatletter \def\ps@copyright{} \makeatother \fvset{frame=lines,framerule=0.1pt,framesep=8pt,numbers=none,xleftmargin=5ex,fontfamily=tt,fontsize=\small} \newenvironment{screen}{\vspace{1ex}\Verbatim}{\endVerbatim\vspace{1ex}} \begin{document} \begin{flushright} AEI-2006-037\\cs.SC/0608005 \end{flushright} \begin{frontmatter} %\title{Cadabra: a field-theory motivated symbolic computer algebra %system} \title{A field-theory motivated approach to symbolic computer algebra} \author{Kasper Peeters} \address{Max-Planck-Institut f\"ur Gravitationsphysik, Albert-Einstein-Institut\\Am M\"uhlenberg 1, 14476 Golm, GERMANY} \ead{kasper.peeters@aei.mpg.de} \begin{abstract} Field theory is an area in physics with a deceptively compact notation. Although general purpose computer algebra systems, built around generic list-based data structures, can be used to represent and manipulate field-theory expressions, this often leads to cumbersome input formats, unexpected side-effects, or the need for a lot of special-purpose code. This makes a direct translation of problems from paper to computer and back needlessly time-consuming and error-prone. A prototype computer algebra system is presented which features \TeX-like input, graph data structures, lists with Young-tableaux symmetries and a multiple-inheritance property system. The usefulness of this approach is illustrated with a number of explicit field-theory problems. \end{abstract} \end{frontmatter} % 11.10.-z Field theory (for gauge field theories, see 11.15.-q) % 02.70.Wz Symbolic computation (computer algebra) \section{Field theory versus general-purpose computer algebra} For good reasons, the area of general-purpose computer algebra programs has historically been dominated by what one could call ``list-based'' systems. These are systems which are centred on the idea that, at the lowest level, mathematical expressions are nothing else but nested lists (or equivalently: nested functions, trees, directed acyclic graphs,~\ldots). There is no doubt that a lot of mathematics indeed maps elegantly to problems concerning the manipulation of nested lists, as the success of a large class of LISP-based computer algebra systems illustrates (either implemented in LISP itself or in another language with appropriate list data structures). However, there are certain problems for which a pure list-based approach may not be the most elegant, efficient or robust one. That a pure list-based approach does not necessarily lead to the fastest algorithms is of course well-known. For e.g.~polynomial manipulation, there exists a multitude of other representations which are often more appropriate for the problem at hand. An area for which the limits of a pure list-based approach have received less attention consists of what one might call ``field theory'' problems. Without attempting to define this term rigorously, one can have in mind problems such as the manipulation of Lagrangians, field equations or symmetry algebras; the examples discussed later will define the class of problems more explicitly. The standard physics notation in this field is deceptively compact, and as a result it is easy to overlook the amount of information that is being manipulated when one handles these problems with pencil and paper. As a consequence, problems such as deriving the equations of motion from an action, or verifying supersymmetry or BRST invariance, often become a tedious transcription exercise when one attempts to do them with existing general-purpose computer algebra systems. Here, the inadequateness of simple lists is not so much that it leads to sub-optimal, slow solutions (although this certainly also plays a role at some stage), but rather that it prevents solutions from being developed at~all. To make the problems more concrete, let us consider a totally arbitrary example of the type of expressions which appear in field theory. A typical Lagrangian or Noether charge might contain terms of the type \begin{equation} \label{e:ex1} \int\!{\rm d}^nx\, \frac{\partial}{\partial x^\lambda} \Big(F_{\mu\nu\rho}\, \psi^{\mu} \Big)\, \psi^{\nu}\,. \end{equation} Let us take, purely as an example, ~$F_{\mu\nu\rho}$ to be a commuting field strength of some two-form field, $\psi^\mu$ an anti-commuting vector, and $x^\mu$ to label an~$n$-dimensional space. Traditionally, one would represent~\eqref{e:ex1} in the computer as a nested list, which in tree-form would take the form\vspace{2ex} \begin{center} \includegraphics[height=5cm]{exp2.eps}\\[2ex] \end{center} The precise details do not matter here; the important point is that the expression takes the form of a multiply nested list. However, this list can only be the starting point, since expression~\eqref{e:ex1} clearly contains much more information than just the tree structure. This leads to a number of ``standard'' problems which field-theory computer algebra systems have to face: \medskip \begin{itemize} \item The names of contracted indices do not matter, in fact, it is only the contraction which is relevant. The nested list structure does not capture the cyclic graph-structure inherent in the expression. How do we make a list-based program aware of this fact, especially when doing substitutions? (this problem is more colloquially known as the ``dummy index'' problem). \item The expression is, for the ``outside world'', an object with two free indices, $\lambda$ and $\rho$. However, these indices, or graph edges, occur at different depths in the tree. How can we access the nested list by the free edges of the tree? \item The reason why $F$ and $\psi$ should stay as children of the diff node is that they depend on~$x$. Where do we store this information? And how do we make algorithms aware of~it? \item The diff and $\psi$ child nodes of the prod node cannot be moved through each other, because the diff node contains a $\psi$. In other words, the diff node ``inherits'' the anti-commutativity from one of its child nodes. How do we handle this? \item The anti-symmetry of~$F$ relates several contraction patterns. However, there are more complicated symmetries present in the expression. The Bianchi identity on the field strength, for instance, is a multi-term relation involving the indices on~$F$ and the index on diff. How do we make the program aware of this identity, and how do we take it into account when reducing expressions to a canonical form? \item For physicists, the simplest way to write expressions such as~\eqref{e:ex1} is to use \TeX{} notation, for example \begin{equation*} \verb|\int d^nx \partial_{\lambda} ( F_{\mu\nu\rho} \psi^{\mu} ) \psi^{\nu}| \end{equation*} Being able to input expressions like this would eliminate a large number of errors in transcribing physics problems to computer algebra systems, and make it much easier to use the computer as a scratch pad for tedious calculations (in particular, it would eliminate a good part of the learning curve of the program). Although \TeX{} notation certainly lacks the semantics to be used as input language for a generic computer algebra system (see e.g.~\cite{fateman99parsing} for a discussion of this problem), it is not hard to come up with a subset of \TeX{} notation which is both easily understandable and mathematically unambiguous. But how do we teach an existing general purpose system to deal with input of this type? \end{itemize} \medskip This collection of problems suggest that a general-purpose system based on ``nested lists'' is a rather bare-bones tool to describe field-theory problems. The nested list is just one of the many possible views or representations of the (rather heavily labelled) graph structure representing the expression. While it is perfectly possible to tackle many of the problems mentioned above in a list-based system (as several tensor algebra packages for general purpose computer algebra systems illustrate~\cite{e_xact,e_balf1,Klioner:1997sv,parker1}), this may not be the most elegant, efficient or robust approach (the lack of a system which is able to solve all of the sample problems in section~\ref{s:examples} in an elegant way exemplifies this point). By endowing the core of the computer algebra system with data structures which are more appropriate for the storage of field-theory expressions, it becomes much simpler to write a computer algebra system which can resolve the problems listed above.\footnote{There are of course \emph{other subclasses} of field-theory problems for which some of the points raised here are irrelevant and efficient computer algebra systems have been developed; see e.g.~\cite{Vermaseren:2000nd} for an example.} The remainder of this paper describes the key ingredients in an approach taken in the prototype computer algebra system ``cadabra''. Full details of this program, including source code, binaries and a reference manual, can be found at the web site~\cite{kas_cdb}. \section{Design goals and implementation} \label{s:structure} This section describes in more detail the main features of the cadabra program: the internal graph views of the tree structure, its handling of node symmetries and the use of a multiple-inheritance property system. In addition to these features, cadabra also has a number of other characteristics which make it especially tuned to the manipulation of ``field theory'' problems. An important characteristic which should not remain unmentioned is the fact that cadabra accepts \TeX{}-like notation for tensorial expressions, making it much easier to transcribe problems from and to paper. The program can be used both from a text-based command-line interface as well as from a graphical front-end or from within \TeX{}macs~\cite{vdH:Gut}. I will not discuss the \TeX{} input/output in detail, but examples can be found in section~\ref{s:examples}. \subsection{Graph structure} \label{s:graph} Cadabra is a standalone program written in~\Cpp. As in most other computer algebra systems, the internal data storage used in cadabra is that of a tree. Concretely, this is implemented using a custom tree container class~\cite{kas_tree} based on STL ideas~\cite{b_muss1}. However, what sets the program apart from other systems is that a)~the tree structure contains more data than usual, to make it easier to represent field-theory problems in a compact way, and b)~the tree manipulation algorithms offer several ways of viewing and modifying this tree. In more detail: \medskip \begin{itemize} \item The nodes of the tree carry so-called ``parent-relation'' information, which determine how child nodes are related to parent nodes. As an example of such a relation, consider the expression~$T^{\mu}{}_{\nu}(x)$. This is stored as a node~$T$, with three children~$\mu$, $\nu$ and $x$, which have parent relations ``superscript'', ``subscript'' and ``argument'' respectively (more relations can easily be added in the future if necessary). A common way of storing this information is e.g.~\mbox{\tt T[mu, -nu, x]} or \mbox{\tt T[up[mu], dn[nu], x]}, but both have their disadvantages: the first form does not allow us to store~$T^{-\mu}{}_{\nu}(x)$, while the second form introduces an additional layer of overhead. A format similar to the second case is also used in Stensor~\cite{maccallum1}, albeit using a different syntax; it has the disadvantage that it is neither a very convenient representation for the computer (especially not when the implementation is in \Cpp), nor a representation which is convenient for the user, as it is quite distinct from \TeX{} notation. \item The tree class not only provides a way to access the nodes of the graph by pre- or post-order traversal, but also provides iterators which access e.g.~only all indices of a node. In the example~\eqref{e:ex1}, an index iterator acting on the {\tt diff} node would return, in turn, the~$\mu$, $\nu$, $\rho$, $\mu$ and $\lambda$ indices. This makes it easy to write fast low-level routines which deal directly with the tensor structure of an expression. \item The tree manipulation algorithms are aware of the meaning of ``contracted nodes'' (contracted indices). Whenever one expression graph is inserted into another one, the algorithms automatically ensure that labels which are used to denote contracted indices (i.e.~edges which connect two nodes) are relabelled appropriately. Names are chosen by using property lists (see section~\ref{s:properties}). \item The contraction detection mechanism can deal with sub- or superscripts which do not denote indices, as in e.g.~$A^\dagger$. This is achieved by attaching a special property to the symbol (see section~\ref{s:properties} for more details). \end{itemize} \medskip The enhanced tree structure can be modified at the level of the user interface through standard list manipulation commands, or at the level of custom modules written in~\Cpp. \subsection{Symmetries} \label{s:symmetries} A second issue which cadabra addresses differently from other computer algebra systems is that of node symmetries. It is common in computer algebra systems that there is a generic way to specify so-called \emph{mono-term} symmetries. These are symmetries which relate one particular ordering of arguments to another one, up to a possible overall sign. Cadabra can of course find canonical representations for tensors with mono-term symmetries (using an external implementation~\cite{e_xact} of the double-coset algorithm~\cite{port2}; an alternative backtracking algorithm for mono-term symmetries is described in~\cite{dres1}). However, mono-term symmetries do not exhaust the symmetries of tensors transforming in generic representations of the Lorentz group. They do not include Garnir symmetries of Young tableaux. Examples of such symmetries are the Ricci identity for Riemann tensors, \begin{equation} R_{m n p q} + R_{m p q n} + R_{m q n p} = 0\,, \end{equation} or the Bianchi identity for field strengths. These identities relate more than two terms, and are therefore also called \emph{multi-term} symmetries. Despite the clear importance of being able to take such identities into account, there are very few computer algebra systems which have implemented a solution. The implementation in~\cite{parker1} simply uses a large set of transformation rules for Riemann tensor monomials. These rules were constructed by hand, and are only available for Riemann tensor monomials up to third order (i.e.~it would require tedious work to construct such rules for more general expressions, involving more than just the Riemann or Ricci tensors). An alternative approach is taken in~\cite{maccallum1,ilyi1,e_balf1}, in which the set of all identities for a particular tensor is used to rewrite a given expression in canonical form. This idea of handling multi-term symmetries using a sum-substitution algorithm goes back to at least~\cite{hornf1}. Cadabra, instead, uses Young projector methods internally for all index symmetry handling. The underlying idea is that by applying a Young projector to a tensor, its multi-term symmetries become manifest. This allows one to construct a basis of tensor monomials constructed from arbitrary tensors, and to decompose a given monomial on any preferred basis.\footnote{In order to determine the number of terms in a basis of monomials of tensors, cadabra relies on an external program for the computation of tensor product representations (using the LiE program~\cite{e_cohe1}).} This method was first described in~\cite{Green:2005qr}. For e.g.~Riemann tensors, the idea is to replace all tensors by their equivalent form \begin{equation} \label{e:Rproj} R_{a b c d} \rightarrow \tfrac{1}{3}\big( 2\, R_{a b c d} - R_{a d b c} + R_{a c b d} \big)\,. \end{equation} The expression on the right-hand side manifestly satisfies the cyclic Ricci identity, even if one only knows about the mono-term symmetries of the Riemann tensor. Using the projector~\eqref{e:Rproj} it is easy to show e.g.~that~$2\,R_{a b c d} R_{a c b d} = R_{a b c d} R_{a b c d}$. The monomial on the left-hand side maps to \begin{equation} \begin{aligned} R_{a b c d} R_{a c b d} \rightarrow \tfrac{1}{3} \big( R_{a b c d} R_{a c b d} + R_{a b c d} R_{a b c d} \big)\,, \end{aligned} \end{equation} while $R_{a b c d} R_{a b c d}$ maps to twice this expression, thereby proving the identity. Writing each term in a sum in a canonical form by using~\eqref{e:Rproj} would typically lead to extremely large expressions, and not be very convenient for subsequent calculations. However, the same algorithm can also be used to write a sum in a ``minimal'' form.\footnote{``Minimal'' here does not necessarily mean that the expression has been reduced to the shortest possible form, which is a problem which to the best of my knowledge remains unresolved. That is, while the algorithm removes dependent terms, as in $2\,R_{a b c d} + 2\,R_{b c a d} + R_{c a b d} \rightarrow R_{a b c d} + R_{b c a d}$ (because the third term is found to be expressible as a linear combination of the first two), it does not reduce this further to $- R_{c a b d}$ (typical cases are of course more complicated than this example).} That is, by projecting each term using~\eqref{e:Rproj} the program can perform the simplification \begin{equation} R_{a b c d} R_{a c b d} + R_{a b c d} R_{a b c d} \rightarrow 3\,R_{a b c d} R_{a c b d}\,, \end{equation} i.e.~express the second term in terms of the first one. This does not define a canonical form (the expression could equally well have been written using~$R_{a b c d} R_{a b c d}$), but it does systematically eliminate terms which can be written as linear combinations of other terms. \subsection{Properties} \label{s:properties} A third problem for which cadabra takes a different approach from other systems is that of ``typing'' of symbols and expressions. In cadabra, the meaning of symbols or expressions is determined by associating \emph{properties} to them. Properties can be simple, such as ``being an integer'', or ``being anti-symmetric in all indices'', or ``being an index which is not to be summed over'' (cf.~the discussion in section~\ref{s:graph}). They can also be more complicated and composite, such as ``being an anti-commuting spinor in the left-handed Weyl representation of the eight-dimensional Lorentz group''. The general problem of deducing properties of composite objects from the properties of their constituents is a hard (see e.g~\cite{weib1}). Cadabra takes a pragmatic approach, trying to provide a useful property system for concrete problems rather than trying to be complete or mathematically rigorous. Properties are implemented as a standard multiple-inheritance tree of \Cpp objects. The association to symbols is stored in a map, which relates patterns to pointers to property objects.\footnote{It is important that such properties are implemented at a low level. Most computer algebra systems would allow one to implement e.g.~handling of sets of non-commuting objects using user-defined property testing functions and appropriate transformation rules. It is a much harder problem to make sure that all routines of the underlying system use these properties efficiently and correctly.} This makes it relatively easy to make properties inherit from each other. An example of an inherited property is the property {\tt PartialDerivative}, which inherits from {\tt TableauBase}, so that the symmetry information of objects on which a partial derivative acts are automatically propagated. Nodes can inherit properties from child nodes. A simple situation in which this is useful is for instance when one uses accents to mark symbols, as in e.g.~$\bar{\psi} \psi$. If {\tt \bs{}psi} is declared to be self-anticommuting, we obviously want the~{\tt \bs{}bar\{\bs{}psi\}} tree to have this property as well. When scanning for properties of nodes, the internal algorithms take into account such inheritance of properties. Inheritance of a property is, itself, again implemented as a property (in the example above, the {\tt \bs{}bar} node is declared to have the property {\tt PropertyInherit}, while more fine-tuned inheritance is implemented by deriving from a templated {\tt Inherit} class, as in e.g.~{\tt Inherit}).\footnote{This is similar to Macsyma's types and features: the property which is attached to a symbol is like a `type', while all properties which the symbol inherits from child nodes are like `features'. Property inheritance can also be found other systems, e.g.~Axiom~\cite{daly1}.} Not all property inheritance is, however, as simple as propagating the information up from a deeper lying node. More complicated property inheritance occurs when nodes have to ``compute'' their properties from properties of the child nodes. This occurs for instance when we want to know how products of symbols commute among each other. For such cases, there are more complicated property classes, for instance {\tt CommutingAsProduct} or {\tt CommutingAsSum}. Similarly, there is a property {\tt IndexInherit} which indicate that nodes should make the indices of their child nodes visible to the outside world. Other composite property objects can easily be added to the system. \section{Typical examples} \label{s:examples} In this section, the three main points discussed in the previous section main text (enhanced tree data structures \& algorithms, the use of representation theory to classify object symmetries, and the use of properties) will be illustrated with a number of explicit examples. These examples are meant to be readable without further information about the program language. As such, they also illustrate the ease with which tensorial expressions can be fed into the program. Full details of the input language and transformation algorithms can be found in the manual~\cite{kas_cdb}. \subsection{Index handling and substitution} When doing computations by hand, we do index relabelling almost automatically when a clash occurs. However, unless the computer program is aware of this problem at a low level, clashes are bound to occur frequently. Consider first the standard type of relabelling, illustrated by the expressions \begin{equation} C = A^2\,,\quad \text{with}\quad A = B_{m n} B_{m n}\quad\text{and}\quad B_{n p} = T_{m n} T_{m p}\,. \end{equation} In cadabra one can e.g.~do\footnote{As alluded to in the first section, the notation used here is not generic~\TeX{} but rather a well-defined subset, with some additional conventions required to make the input unambiguous. An example of such a convention is the use of spaces to separate indices; further details about the input format conventions can be found in the reference manual~\cite{kas_cdb}.} \begin{screen} {m,n,p,q#}::Indices(vector). C:= A A; @substitute!(%)( A = B_{m n} B_{m n} ); @substitute!(%)( B_{n p} = T_{m n} T_{m p} ); \end{screen} where the meaning of the hash symbol on the declaration of the~$q$ index (in the first line) will become clear soon. The result is \begin{screen} C:= T_{q2 m} T_{q2 n} T_{q3 m} T_{q3 n} T_{q4 p} T_{q4 q1} T_{q5 p} T_{q5 q1}; \end{screen} This type of relabelling and automatic index generation is not an entirely uncommon feature to find in tensor algebra systems, although it is often implemented in an add-on package. The situation becomes more complicated when we have indices which do not occur at the same level, for instance \begin{equation} C = A^2\,,\quad \text{with} \quad A = \partial_m (B_n B_p + C_{n p} ) B_{m n p}\quad\text{and}\quad B_n = T_{n m} S_{m}\,. \end{equation} Few systems know how to deal with these types of expressions elegantly (i.e.~without requiring a cumbersome input format). The reason is that the derivative carries an index, but the objects in the product on which it acts carry indices too, and these indices do not all occur at the same depth of the expression tree. The cadabra instructions, however, remain equally simple as in the previous example, \begin{screen} {m,n,p,q#}::Indices(vector). \partial{#}::Derivative. C:= A A; @substitute!(%)( A = \partial_{m}( B_n B_p + C_{n p} ) B_{m n p} ); @substitute!(%)( B_n = T_{n m} S_{m} ); \end{screen} The result comes out as the expected \begin{screen} C:= \partial_{m}(T_{n q4} S_{q4} T_{p q5} S_{q5} + C_{n p}) B_{m n p} \partial_{q1}(T_{q2 q6} S_{q6} T_{q3 q7} S_{q7} + C_{q2 q3}) B_{q1 q2 q3}; \end{screen} Finally, it of course happens frequently that more than one type of index appears in an expression, labelling tensors in different spaces. Consider for instance, \begin{equation} C = A^2\quad\text{with}\quad A_{m \mu} = \bar{\psi}\Gamma_{m p} \psi\, B_{p \mu}\,, \end{equation} where the roman and Greek indices cannot be interchanged at will, because they refer to flat and curved spaces respectively. This example translates to \begin{screen} {\mu, \rho, \nu#}::Indices(curved). {m, n, p, q#}::Indices(flat). C:= A_{m \nu} A_{m \nu}; @substitute!(%)( A_{m \mu} = \bar{\psi}\Gamma_{m p} \psi B_{p \mu \rho} C_{\rho}); \end{screen} with the expected result \begin{screen} C:= \bar{\psi} \Gamma_{m p} \psi B_{p \nu \rho} C_{\rho} \bar{\psi} \Gamma_{m n} \psi B_{n \nu \mu} C_{\mu}; \end{screen} All this type of relabelling is done by the internal tree manipulation algorithms, which ensures that no algorithm can lead to inconsistent expressions. New dummy indices are taken from the appropriate sets, using the property information associated to the various indices. \subsection{Canonicalisation and Young-tableaux methods} As long as one deals only with symmetric or antisymmetric tensors, many computer algebra systems are able to write tensor monomials in a canonical form (although efficient algorithms for very large numbers of indices or very large numbers of identical tensors have only surfaced relatively recently, see~\cite{Portugal:1998qi,port2,e_xact,e_canon}). Generic algorithms for multi-term Garnir symmetries, such as the Ricci or Bianchi identity, are much less widespread; see the discussion in section~\ref{s:symmetries}. Cadabra is the first system to label tensors by Young tableaux and to use Young projector methods to handle multi-term symmetries. A common problem in which multi-term symmetries play an important role is the construction of a basis of all tensor monomials of a given length dimension. Determining the number of elements of such a basis is a relatively straightforward exercise in group theory~\cite{Fulling:1992vm}. In order to actually construct the basis, cadabra uses the Young projector method described in the appendix of~\cite{Green:2005qr}. As an example, let us construct a basis of monomials cubic in the Riemann tensor, \begin{screen} {m,n,p,q,r,s,t,u,v,w,a,b}::Indices(vector). {m,n,p,q,r,s,t,u,v,w,a,b}::Integer(0..9). R_{m n p q}::RiemannTensor. basisR3:= R_{m n p q} R_{r s t u} R_{v w a b}; @all_contractions(%); @canonicalise!(%): @substitute!(%)( R_{m n m n} -> R ): @substitute!(%)( R_{m n m p} -> R_{n p} ); \end{screen} After a declaration of the objects to be used, the program determines in one step all possible independent contractions of three Riemann tensors. The last two lines only serve to rewrite the result in terms of Ricci tensors and scalars, after which the output takes the form \begin{screen} basisR3:= \{ R_{m n p q} R_{m p r s} R_{n r q s}, R R_{q r} R_{q r}, R_{n p} R_{n q p r} R_{q r}, R_{n p} R_{n q r s} R_{p r q s}, R R_{p q r s} R_{p q r s}, R_{n p} R_{n r} R_{p r}, R_{m n p q} R_{m r p s} R_{n r q s}, R R R \}; \end{screen} This result is equivalent to the basis given in the ``${\mathcal R}^0_{6,3}$'' table on page~1184 of~\cite{Fulling:1992vm}. It is also possible to decompose any given tensor monomial on a previously constructed basis. Take for example the basis of Weyl tensor monomials of fourth order. This basis can be read off from the tables of~\cite{Fulling:1992vm}, \begin{equation} \begin{aligned} W_1 &= W_{m n a b} W_{n p b c} W_{p s c d} W_{s m d a}\,,\\[1ex] W_2 &= W_{m n a b} W_{n p b c} W_{m s c d} W_{s p d a}\,,\\[1ex] W_3 &= W_{m n a b} W_{p s b a} W_{m n c d} W_{p s d c}\,,\\[1ex] W_4 &= W_{m n a b} W_{m n b a} W_{p s c d} W_{p s d c}\,,\\[1ex] W_5 &= W_{m n a b} W_{n p b a} W_{p s c d} W_{s m d c}\,,\\[1ex] W_6 &= W_{m n a b} W_{p s b a} W_{m p c d} W_{n s d c}\,,\\[1ex] W_7 &= W_{m n}{}^{[m n} W_{p q}{}^{p q} W_{r s}{}^{r s} W_{t u}{}^{t u]}\,. \end{aligned} \end{equation} If we want to find the decomposition \begin{equation} W_{p q r s} W_{p t r u} W_{t v q w} W_{u v s w}- W_{p q r s} W_{p q t u} W_{r v t w} W_{s v u w} = W_2 - \tfrac{1}{4} W_6\,, \end{equation} using ``classical'' methods, we would need to figure out the right way to repeatedly apply the Ricci cyclic identity to the left-hand side of this expression. The appropriate program to decompose the left-hand side on the seven-term basis and prove this identity is \begin{screen} {m,n,p,q,r,s,t,u,v,w,a,b,c,d,e,f}::Indices(vector). W_{m n p q}::WeylTensor. W1:= W_{m n a b} W_{n p b c} W_{p s c d} W_{s m d a}; W2:= W_{m n a b} W_{n p b c} W_{m s c d} W_{s p d a}; W3:= W_{m n a b} W_{p s b a} W_{m n c d} W_{p s d c}; W4:= W_{m n a b} W_{m n b a} W_{p s c d} W_{p s d c}; W5:= W_{m n a b} W_{n p b a} W_{p s c d} W_{s m d c}; W6:= W_{m n a b} W_{p s b a} W_{m p c d} W_{n s d c}; W7:= W_{m n}^{m n} W_{p q}^{p q} W_{r s}^{r s} W_{t u}^{t u}; @asym!(%){^{m},^{n},^{p},^{q},^{r},^{s},^{t},^{u}}: @substitute!(%)( W_{a b}^{c d} -> W_{a b c d} ): @indexsort!(%): @collect_terms!(%): @canonicalise!(%): @collect_terms!(%); basisW4:= { @(W1), @(W2), @(W3), @(W4), @(W5), @(W6), @(W7) }; W_{p q r s} W_{p t r u} W_{t v q w} W_{u v s w} - W_{p q r s} W_{p q t u} W_{r v t w} W_{s v u w}; @decompose!(%){ @(basisW4) }; @list_sum!(%); @collect_terms!(%); \end{screen} Most of this code is self-explanatory. The first two lines declare the symbols and objects to be used, the next block of lines declares the basis and performs the eight-fold anti-symmetrisation for the last basis element.\footnote{Commands such as {\tt @collect\_terms} can be added to a list of default rules to be applied automatically; they have been included here so that all steps are explicit.} The decomposition is done with the last three lines. The final output of this small program reads \begin{screen} {0, 1, 0, 0, 0, -1/4, 0 }; \end{screen} Internally, this involved a Young-projection of all tensors in the basis, a projection of the tensors in the expression which we want to decompose, and a solution of a system of linear equations~\cite{Green:2005qr}. The internal algorithm is completely generic and applies to tensor monomials with arbitrary symmetries. \subsection{Properties and property inheritance} A typical class of problems in which one handles tensors of both commuting and anti-commuting type is the construction of supersymmetric actions. This class of problems also shows the use of implicit dependence of tensors on coordinates, as well as inheritance of spinor and anti-commutativity properties. Consider as a trivial example -- which is nevertheless not easy to reproduce with other computer algebra systems -- the invariance of the super-Maxwell action \begin{equation} S = \int\!{\rm d^4}x\, \Big[ -\frac{1}{4} (f_{ab})^2 - \frac{1}{2}\bar{\lambda}\gamma^a \partial_a \lambda\Big]\,, \end{equation} (where~$f_{ab} = \partial_a A_b - \partial_b A_a$) under the transformations \begin{equation} \delta A_a = \bar{\epsilon}\gamma_a \lambda\,,\quad \delta \lambda = -\frac{1}{2} \gamma^{a b} \epsilon\, f_{a b}\,. \end{equation} The object properties for this problem are \begin{screen} { a,b,c,d,e }::Indices(vector). \bar{#}::DiracBar. { \partial{#}, \ppartial{#} }::PartialDerivative. { A_{a}, f_{a b} }::Depends(\partial, \ppartial). { \epsilon, \gamma_{#} }::Depends(\bar). \lambda::Depends(\bar, \partial). { \lambda, \gamma_{#} }::NonCommuting. { \lambda, \epsilon }::Spinor(dimension=4, type=Majorana). { \epsilon, \lambda }::SortOrder. { \epsilon, \lambda }::AntiCommuting. \lambda::SelfAntiCommuting. \gamma_{#}::GammaMatrix. \delta{#}::Accent. f_{a b}::AntiSymmetric. \delta_{a b}::KroneckerDelta. \end{screen} Note the use of two types of properties: those which apply to a single object, like {\tt Depends}, and those which are associated to a list of objects, like {\tt AntiCommuting}. Clearly $\partial_a \lambda$ and $\epsilon$ are anti-commuting too, but the program figures this out automatically from the fact that {\tt $\backslash$partial} has a {\tt PartialDerivative} property associated to it. The actual calculation is an almost direct transcription of the calculation one would do by hand.\footnote{This example makes use of a set of default rules, to wit ``{\tt ::PostDefaultRules( @@prodsort!(\%), @@rename\_dummies!(\%), @@canonicalise!(\%), @@collect\_terms!(\%) )}'', which mimick the automatic rewriting behaviour of many other computer algebra systems and get invoked automatically at each step. See~\cite{kas_cdb} for more details.} First we define the supersymmetry transformation rules and the action, which can be entered as in~\TeX{}, \begin{screen} susy:= { \delta{A_{a}} = \bar{\epsilon} \gamma_{a} \lambda, \delta{\lambda} = -(1/2) \gamma_{a b} \epsilon f_{a b} }; S:= -(1/4) f_{a b} f_{a b} - (1/2) \bar{\lambda} \gamma_{a} \partial_{a}{\lambda}; \end{screen} Showing invariance starts by applying a variational derivative, \begin{screen} @vary!(%)( f_{a b} -> \partial_{a}{\delta{A_{b}}} - \partial_{b}{\delta{A_{a}}}, \lambda -> \delta{\lambda} ); @distribute!(%); @substitute!(%)( @(susy) ): @prodrule!(%): @distribute!(%): @unwrap!(%); \end{screen} After these steps, the result is (shown exactly as it appears in the graphical and the \TeX{}macs~\cite{vdH:Gut} front-ends)% \begin{equation} S = \bar{\epsilon} \gamma_{a} \partial_{b} \lambda\, f_{ab} + \frac{1}{4} \overline{\gamma_{ab} \epsilon} \gamma_{c} \partial_c\lambda\, f_{ab} + \frac{1}{4} \bar{\lambda}\gamma_a \gamma_{bc} \epsilon \partial_a f_{bc}\,. \end{equation} Since the program knows about the properties of gamma matrices it can rewrite the Dirac bar, and then we do one further partial integration, \begin{screen} @rewrite_diracbar!(%); @substitute!(%)( \partial_{c}{f_{a b}} -> \ppartial_{c}{f_{a b}} ): @pintegrate!(%){\ppartial}: @rename!(%){"\ppartial"}{"\partial"}: @prodrule!(%): @unwrap!(%); \end{screen} What remains is the gamma matrix algebra, a rewriting of the derivative of the Dirac bar as the Dirac bar of a derivative, and sorting of spinors (which employs inheritance of the {\tt Spinor} and {\tt AntiCommuting} properties as already alluded to earlier), \begin{screen} @join!(%){expand}: @distribute!(%): @eliminate_kr!(%): @substitute!(%)( \partial_{a}{\bar{\lambda}} -> \bar{\partial_{a}{\lambda}} ); @spinorsort!(%): \end{screen} The result is (after partial integration) a Bianchi identity on the field strength, and thus invariance of the action. While this example is rather simple, and does not require a computer algebra system for its solution, it illustrates that the extended tree structure together with the property system make it possible to manipulate expressions in a way which closely resembles what one would do when solving the problem with pencil and paper. Several more complicated examples will be discussed in the upcoming~\cite{kas_cdb_hep}. \section{Summary} I have presented a new prototype computer algebra system which is designed to be an easy-to-use scratch pad for problems encountered in field theory. The current library of algorithms include functionality to deal with bosonic and fermionic tensors, spinors, gamma matrices, differential operators and so on, all through the use of a multiple-inheritance property mechanism. Cadabra is the first system which handles generic multi-term tensor symmetries using a Young-projector based algorithm. It is also the first system which accepts input in~\TeX{} form, eliminating tedious translation steps and making programs much easier to read for new users. Finally, the source code of the system is freely available and the reference guide contains extensive documentation explaining how to add new algorithm modules to the program. \section*{Acknowledgements} I am grateful to Jos\'e Martin-Garcia for inspiring discussions and for help with the use of his {\tt xPerm} code~\cite{e_xact} for mono-term canonicalisation. I thank the anonymous referee for extensive comments which have substantially improved this paper. \setlength{\bibsep}{4pt} %\bibliographystyle{kasper} %\bibliography{kasbib} \begingroup\raggedright\begin{thebibliography}{23} \expandafter\ifx\csname natexlab\endcsname\relax\def\natexlab#1{#1}\fi \bibitem[Fateman and Caspi(1999)]{fateman99parsing} R.~J. Fateman and E.~Caspi, ``Parsing {{\TeX}} into mathematics'', {\em SIGSAM Bulletin (ACM Special Interest Group on Symbolic and Algebraic Manipulation)} {\bf 33} (1999), no.~3, 26. \bibitem[Martin-Garcia(????)]{e_xact} J.~Martin-Garcia, ``{xPerm and xAct}'', \url{http://metric.iem.csic.es/Martin-Garcia/xAct/index.html}. \bibitem[{Balfag\'on} et~al.(????){Balfag\'on}, {Castellv\'\i}, and {Ja\'en}]{e_balf1} A.~{Balfag\'on}, P.~{Castellv\'\i}, and X.~{Ja\'en}, ``Tools of tensor calculus'', \url{http://baldufa.upc.es/xjaen/ttc/}. \bibitem[Klioner(1997)]{Klioner:1997sv} S.~A. Klioner, ``{EinS: A Mathematica package for computations with indexed objects}'', \href{http://xxx.lanl.gov/abs/gr-qc/0011012}{{\tt gr-qc/0011012}}. %%CITATION = GR-QC 0011012;%%. \bibitem[Parker and Christensen(1994)]{parker1} L.~Parker and S.~M. Christensen, ``Mathtensor : A system for doing tensor analysis by computer'', Addison-Wesley, 1994. \bibitem[Vermaseren(2000)]{Vermaseren:2000nd} J.~A.~M. Vermaseren, ``New features of {FORM}'', \href{http://xxx.lanl.gov/abs/math-ph/0010025}{{\tt math-ph/0010025}}. %%CITATION = MATH-PH 0010025;%%. \bibitem[Peeters(2006)]{kas_cdb} K.~Peeters, ``Cadabra: tutorial and reference guide'', 2006, \url{http://www.aei.mpg.de/~peekas/cadabra/}. \bibitem[van~der Hoeven(2001)]{vdH:Gut} J.~van~der Hoeven, ``{GNU TeXmacs: A free, structured, wysiwyg and technical text editor}'', in ``Le document au XXI-i\`eme si\`ecle'', D.~Flipo, ed., vol.~39--40, pp.~39--50. \newblock Metz, 14--17 mai 2001. \newblock Actes du congr\`es GUTenberg. \url{http://www.texmacs.org}. \bibitem[Peeters(2006)]{kas_tree} K.~Peeters, ``Tree.hh'', 2006, \url{http://www.aei.mpg.de/~peekas/tree/}. \bibitem[Musser and Saini(1996)]{b_muss1} D.~R. Musser and A.~Saini, ``{STL} tutorial and reference guide, {C++} programming with the standard template library'', Addison Wesley, 1996. \bibitem[MacCallum and Skea(1994)]{maccallum1} M.~A.~H. MacCallum and J.~E.~F. Skea, ``{SHEEP: A computer algebra system for general relativity}'', in ``Algebraic computing in general relativity'', M.~J. {Rebou\c{c}as} and W.~L. Roque, eds., pp.~1--172. \newblock Oxford, 1994. \bibitem[Portugal(1999)]{port2} R.~Portugal, ``Algorithmic simplification of tensor expressions'', {\em J.\ Phys.} {\bf A32} (1999) 7779--7789. \bibitem[Dresse(1993)]{dres1} A.~Dresse, ``Polynomial poisson structures and dummy variables in computer algebra'', PhD thesis, Universit\'e Libre de Bruxelles, 1993. \bibitem[Ilyin and Kryukov(1996)]{ilyi1} V.~A. Ilyin and A.~P. Kryukov, ``{ATENSOR} - {REDUCE} program for tensor simplification'', {\em Comp.\ Phys.\ Commun.} {\bf 96} (1996) 36--52. \bibitem[Hornfeldt(1979)]{hornf1} L.~Hornfeldt, ``A system for automatic generation of tensor algorithms and indicial tensor calculus, including substitution of sums'', in ``Proceedings of EUROSAM 79'', Ng, ed., vol.~72 of {\em Lecture Notes in Computer Science}, pp.~279--290. \newblock Springer, 1979. \bibitem[Cohen et~al.(1998)Cohen, van Leeuwen, and Lisser]{e_cohe1} A.~Cohen, M.~van Leeuwen, and B.~Lisser, ``{LiE} v.~2.2'', 1998, \url{http://wwwmathlabo.univ-poitiers.fr/~maavl/LiE/}. \bibitem[Green et~al.(2005)Green, Peeters, and Stahn]{Green:2005qr} M.~B. Green, K.~Peeters, and C.~Stahn, ``Superfield integrals in high dimensions'', {\em JHEP\,} {\bf 08} (2005) 093, \href{http://xxx.lanl.gov/abs/hep-th/0506161}{{\tt hep-th/0506161}}. %%CITATION = HEP-TH 0506161;%%. \bibitem[Weiberl and Gonnet(1991)]{weib1} T.~Weiberl and G.~H. Gonnet, ``An algebra of properties'', in ``Proceedings of the ISSAC-91 Conference, Bonn'', pp.~352--359. \newblock 1991. \bibitem[Daly(2005)]{daly1} T.~Daly, ``Axiom volume 1: tutorial'', Lulu press, 2005. \bibitem[Portugal(1998)]{Portugal:1998qi} R.~Portugal, ``An algorithm to simplify tensor expressions'', {\em Comp.\ Phys.\ Commun.} {\bf 115} (1998) 215--230, \href{http://xxx.lanl.gov/abs/gr-qc/9803023}{{\tt gr-qc/9803023}}. %%CITATION = GR-QC 9803023;%%. \bibitem[Portugal(????)]{e_canon} R.~Portugal, ``{The Canon package}'', \url{http://www.cbpf.br/~portugal/Canon.html}. \bibitem[Fulling et~al.(1992)Fulling, King, Wybourne, and Cummins]{Fulling:1992vm} S.~A. Fulling, R.~C. King, B.~G. Wybourne, and C.~J. Cummins, ``Normal forms for tensor polynomials. 1: The {Riemann} tensor'', {\em Class.\ Quant.\ Grav.} {\bf 9} (1992) 1151. %%CITATION = CQGRD,9,1151;%%. \bibitem[Peeters(????)]{kas_cdb_hep} K.~Peeters, ``{Introducing Cadabra: a symbolic computer algebra system for field theory problems}'', {\tt hep-th/0701238}. \end{thebibliography}\endgroup \end{document} cadabra-1.39/doc/properties/000077500000000000000000000000001234107666300157745ustar00rootroot00000000000000cadabra-1.39/doc/properties/Accent.tex000066400000000000000000000011071234107666300177120ustar00rootroot00000000000000\cdbproperty{Accent}{} Turns a symbol into an accent. Accented objects inherit all properties and indices from the objects which they wrap. Here is an example with inherited coordinate dependence: \begin{screen}{1,2,3,4,5,6} \hat{#}::Accent. \partial{#}::PartialDerivative. A::Depends(\partial). \partial(A \hat{A} B): @prodrule!(%): @unwrap!(%); \partial(A) * A * B + A * \partial(\hat{A}) * B; \end{screen} Without the accent property, \verb|\hat{A}| object would be a completely independent object, unrelated to \verb|A|. \cdbseeprop{PropertyInherit} \cdbseeprop{IndexInherit} cadabra-1.39/doc/properties/AntiCommuting.tex000066400000000000000000000041441234107666300212770ustar00rootroot00000000000000\cdbproperty{AntiCommuting}{} Makes components anti-commuting. Example: \begin{screen}{1,2} {A,B}::AntiCommuting. B A; @prodsort!(%); (-1) A B; \end{screen} It also works for objects with indices: \begin{screen}{1,2} {\psi_{m}, \chi}::AntiCommuting. \psi_{m} \chi \psi_{n}; @prodsort!(%); (-1) \chi \psi_{m} \psi_{n}; \end{screen} If you want a pattern like \verb|\psi_{m}| to anti-commute with itself, you should use the \subsprop{SelfAntiCommuting} property instead. You can think about the difference between \subsprop{SelfAntiCommuting} and \subsprop{AntiCommuting} in the following way. If \verb|A_{m n}| is \verb|SelfAntiCommuting|, it means that for each value of the indices the expression \verb|A_{m n}| is an operator which anti-commutes with the operator for any other value of the indices. The matrix~$A$ is thus a matrix of operator-valued components which mutually anti-commute. On the other hand, if \verb|A| and \verb|B| are declared to be \verb|AntiCommuting|, then these can be viewed as two matrices of commuting components, whose matrix product satisfies~$A B = - B A$. If you attach the \verb|AntiCommuting| property to an object with an \subsprop{ImplicitIndex} property, the commutation property does not refer to the object as a whole, but rather to its components. The logic behind that becomes clear when considering e.g.~spinor bilinears \begin{screen}{1,2,3,4,5,6,7,9} {\chi, \psi}::Spinor(dimension=10, type=MajoranaWeyl). {\chi, \psi}::AntiCommuting. \bar{#}::DiracBar. \Gamma{#}::GammaMatrix. {\chi, \psi}::SortOrder. \bar{\psi} \Gamma_{m n p} \chi; @prodsort!(%); @prodsort: not applicable. @spinorsort!(%); \bar{\chi} \Gamma_{m n p} \psi; \end{screen} Here \subscommand{prodsort} did not act because both the spinors and the gamma matrices have the \subsprop{ImplicitIndex} property and there are thus no simple rules for their re-ordering. However, the \subscommand{spinorsort} algorithm did act, and took into account the fact that the components of the spinors are anti-commuting. \cdbseealgo{prodsort} \cdbseealgo{spinorsort} \cdbseeprop{SelfAntiCommuting} \cdbseeprop{Commuting} \cdbseeprop{ImplicitIndex} cadabra-1.39/doc/properties/AntiSelfDual.tex000066400000000000000000000007611234107666300210350ustar00rootroot00000000000000\cdbproperty{AntiSelfDual}{} Make a tensor fully anti-symmetric as well as anti-selfdual. The conventions used are that self-duality means \begin{equation} F_{\mu_1\cdots \mu_n} = - \frac{1}{n!} \epsilon_{\mu_1\cdots\mu_n \mu_{n+1}\cdots \mu_{2n}} F_{\mu_{n+1}\cdots\mu_{2n}}\,. \end{equation} This property used by the Young projection algorithms and the \subscommand{dualise\_tensor} algorithm, among others. \cdbseeprop{SelfDual} \cdbseealgo{dualise_tensor} \cdbseealgo{young_project_tensor} cadabra-1.39/doc/properties/AntiSymmetric.tex000066400000000000000000000005771234107666300213170ustar00rootroot00000000000000\cdbproperty{AntiSymmetric}{} Makes an object antisymmetric in all its indices. Example: \begin{screen}{1,2,3,4} A_{m n}::AntiSymmetric. B_{m n}::Symmetric. A_{m n} B_{m n}; @canonicalise!(%); 0; \end{screen} For more complicated symmetries, use \subsprop{TableauSymmetry}. \cdbseealgo{canonicalise} \cdbseeprop{Symmetric} \cdbseeprop{TableauSymmetry} \cdbseeprop{DAntiSymmetric} cadabra-1.39/doc/properties/Commuting.tex000066400000000000000000000003401234107666300204550ustar00rootroot00000000000000\cdbproperty{Commuting}{} Makes components commuting. This is completely analogous to \subsprop{AntiCommuting} and in fact the default for all objects, so usually does not need to be specified. \cdbseeprop{AntiCommuting} cadabra-1.39/doc/properties/CommutingAsProduct.tex000066400000000000000000000016031234107666300223050ustar00rootroot00000000000000\cdbproperty{CommutingAsProduct}{} This makes an object behave, for purposes of commutation rules, as a product. That is, when trying to move another object through it, the sign that is picked up is determined by moving the other object through all the non-index children. In the example below, \begin{screen}{1,2,3} A(#)::CommutingAsProduct. {Q,X,Y,Z}::AntiCommuting. A(Y)(Z)(Q)*A(X); @prodsort!(%); (-1) A(X) A(Y)(Z)(Q); \end{screen} The minus sign arises because it would also have been present when sorting {\tt (Y*Z*Q)*X}. Note that this does not work when the arguments are given as a list separated by commas, for instance as {\tt A(Y,Z,Q)}. % \begin{screen}{1,2,3} % A(#)::CommutingAsProduct. % \comma{#}::CommutingAsProduct. % {Q,X,Y,Z}::AntiCommuting. % A(Y,Z,Q)*A(X); % @prodsort!(%); % (-1) A(X) A(Y)(Z)(Q); % \end{screen} \cdbseeprop{CommutingAsSum} \cdbseeprop{AntiCommuting} cadabra-1.39/doc/properties/CommutingAsSum.tex000066400000000000000000000010101234107666300214210ustar00rootroot00000000000000\cdbproperty{CommutingAsSum}{} This makes an object behave, for purposes of commutation rules, as a sum. \begin{screen}{1,2,3} A(#)::CommutingAsSum. {Q,X,Y,Z}::AntiCommuting. A(Y)(Z)*A(X); @prodsort!(%); (-1) A(X) A(Y)(Z); \end{screen} The minus sign arises because it would also have been present when sorting the expression {\tt (Y+Z)*X}. Note that this does not (yet) work when the arguments are given as a list separated by commas, as in {\tt A(Y,Z)}. \cdbseeprop{CommutingAsProduct} \cdbseeprop{AntiCommuting} cadabra-1.39/doc/properties/Coordinate.tex000066400000000000000000000010621234107666300206040ustar00rootroot00000000000000\cdbproperty{Coordinate}{} Declare a symbol to be a coordinate label (useful in combination with \subsprop{Depends}). This is required if you want to write a derivative with respect to a coordinate: the input \begin{screen}{1} A(x,x') + \diff{B(x,x')}_{x}; \end{screen} will by default be seen as incorrect because the $x$ in the second term will be considered an index label, not a coordinate. The input \begin{screen}{1,2} { x, x' }::Coordinate. A(x,x') + \diff{B(x,x')}_{x}; \end{screen} is allowed and interpreted in the right way. \cdbseeprop{Symbol} cadabra-1.39/doc/properties/DAntiSymmetric.tex000066400000000000000000000010561234107666300214140ustar00rootroot00000000000000\cdbproperty{DAntiSymmetric}{} Declares an object to have the symmetries of the derivative of a fully anti-symmetric tensor, i.e.~to have a \subsprop{TableauSymmetry} corresponding to a hook-shape Young tableau. \begin{screen}{1,2} DF_{m n p q}::DAntiSymmetric. A_{m n p q}::AntiSymmetric. DF_{m n p q} A^{m n p q}; @impose_bianchi!(%); 0; \end{screen} The symmetries can also be declared directly using \subsprop{TableauSymmetry} but it is usually easier to read the \subsprop{DAntiSymmetric} form. \cdbseeprop{TableauSymmetry} \cdbseeprop{AntiSymmetric} cadabra-1.39/doc/properties/Depends.tex000066400000000000000000000025601234107666300201030ustar00rootroot00000000000000\cdbproperty{Depends}{\it comma separated list of indices, coordinates, derivatives, accents} Makes an object implicitly dependent on other objects, i.e.~assumes that the indicated object is a function of the arguments of the property. For example, \begin{screen}{1,2} x::Coordinate. \phi::Depends(x). \end{screen} makes $\phi$ an implicit function of $x$. Instead of indicating the coordinate on which the object depends, it is also possible to indicate which derivatives would yield a non-zero answer, as in \begin{screen}{1,2} \nabla{#}::Derivative. \phi::Depends(\nabla). \end{screen} Finally, it is possible to use an index name to indicate on which coordinates a field depends, \begin{screen}{1,2} {m,n,p,q}::Indices(vector). \phi::Depends(m). \end{screen} Taking objects out of derivatives (because they do not depend on them) is handled using the \subscommand{unwrap} algorithm. If you want to make an object depend on more than one thing, you need to specify them all in one \subsprop{Depends} property. If you specify them in two separate properties, the last property will overwrite the previous one. Therefore, you get \begin{screen}{1,2,3,4,5,6} \hat{#}::Accent. \partial{#}::PartialDerivative. A::Depends(\hat). A::Depends(\partial). \hat{A}; @unwrap!(%); A; \end{screen} instead of \verb|\hat{A}| which you might have expected. \cdbseealgo{unwrap} \cdbseeprop{Derivative} cadabra-1.39/doc/properties/DependsInherit.tex000066400000000000000000000006711234107666300214270ustar00rootroot00000000000000\cdbproperty{DependsInherit}{} Makes an object inherit all dependencies of the objects they contain. This makes it possible to define functions of objects which behave correctly inside derivatives. \begin{screen}{1,2} f{#}::DependsInherit. x::Coordinate. \partial{#}::PartialDerivative. \phi::Depends(x). \partial_{x}( g f(\phi) ); @unwrap!(%); g \partial_{x}( f(\phi) ); \end{screen} ~ \cdbseealgo{unwrap} \cdbseeprop{PartialDerivative} cadabra-1.39/doc/properties/Derivative.tex000066400000000000000000000016151234107666300206230ustar00rootroot00000000000000\cdbproperty{Derivative}{} An generic derivative object, satisfying the Leibnitz rule. These generic derivatives do not have to commute. \begin{screen}{1,2} D{#}::Derivative. D(A B C); @prodrule!(%); D(A) B C + A D(B) C + A B D(C); \end{screen} Refer to the documentation of \subsprop{PartialDerivative} on how to write derivatives with respect to coordinate indices or coordinates. Make sure to declare the derivative either using the ``with any arguments'' notation as used above (using the hash mark), or by giving an appropriate pattern. The following does not work: \begin{screen}{1,2} D::Derivative. D(A B C); @prodrule!(%); @prodrule: not applicable. \end{screen} The pattern \verb|D| above does not match the expression \verb|D(A B C)| and hence the algorithm does not know that \verb|D(A B C)| is a derivative acting on the product of three objects. \cdbseealgo{prodrule} \cdbseealgo{distribute} cadabra-1.39/doc/properties/Diagonal.tex000066400000000000000000000005521234107666300202360ustar00rootroot00000000000000\cdbproperty{Diagonal}{} Indicates that the object to which the property is attached only has non-zero components on the diagonal, i.e.~when all indices take the same value. \begin{screen}{1,2} \delta_{m n}::Diagonal. \delta_{1 2} \delta_{1 2} - \delta_{1 1} \delta_{2 2}; @canonicalise!(%); - \delta_{1 1}\delta_{2 2}; \end{screen} ~ \cdbseeprop{Coordinate} cadabra-1.39/doc/properties/DiracBar.tex000066400000000000000000000005511234107666300201660ustar00rootroot00000000000000\cdbproperty{DiracBar}{} Declares an object to be the operator which applies the Dirac bar to a spinor, i.e.~an operator which acts according to \begin{equation} \bar{\psi} = i \psi^\dagger \Gamma^0\,. \end{equation} For more information see e.g.~\subscommand{spinorsort} or \subscommand{fierz}. \cdbseeprop{Spinor} \cdbseealgo{spinorsort} \cdbseealgo{fierz} cadabra-1.39/doc/properties/Distributable.tex000066400000000000000000000004601234107666300213130ustar00rootroot00000000000000\cdbproperty{Distributable}{} Makes an object distributable. When the object has a sum as argument, it can be distributed over the terms with \subscommand{distribute}, as in \begin{screen}{1,2,3} \hat{#}::Distributable. \hat{A+B+C D}: @distribute!(%); \hat{A} + \hat{B} + \hat{C D}; \end{screen} ~ cadabra-1.39/doc/properties/EpsilonTensor.tex000066400000000000000000000024311234107666300213220ustar00rootroot00000000000000\cdbproperty{EpsilonTensor}{{\it metric={\sf metric object}, delta={\sf Kronecker delta name}}} A fully anti-symmetric tensor, defined by \begin{equation} \epsilon_{m_1\ldots m_k} := \varepsilon_{m_1\ldots m_k}\,\sqrt{|g|}\,, \end{equation} where the components of~$\varepsilon_{m_1\ldots m_k}$ are 0, $+1$ or $-1$ and~$\varepsilon_{01\cdots k}=1$, independent of the basis, and~$g$ denotes the metric determinant. This property optionally takes a tensor which indicates the symbol which should be used as a \subsprop{KroneckerDelta} symbol when writing out the product of two epsilon tensors. Additionally, it takes a tensor which is the associated metric, from which the signature can be extracted. See the documentation of \subscommand{epsprod2gendelta} for more information on the use of these optional arguments. When the indices are in different positions it is understood that they are simply raised with the metric. This in particular implies \begin{equation} \epsilon^{m_1\ldots m_k} := g^{m_1 n_1} \cdots g^{m_k n_k} \epsilon_{n_1\ldots n_k} = \frac{\varepsilon^{m_1\ldots m_k}}{\sqrt{|g|}}\,, \end{equation} again with~$\varepsilon^{m_1\ldots m_k}$ taking values 0, $+1$ or $-1$ and $\varepsilon^{01\cdots k}=\pm 1$ depending on the signature of the metric. \cdbseealgo{epsprod2gendelta} cadabra-1.39/doc/properties/FilledTableau.tex000066400000000000000000000007541234107666300212210ustar00rootroot00000000000000\cdbproperty{FilledTableau}{\it dimension={\sf integer}} Indicates that the object is a Young tableau with labelled boxes. The arguments of a \subsprop{Tableau} property denote the contents, given as lists, \begin{screen}{1,2} \ftab{#}::FilledTableau. \ftab{a,b,c}{d,e}{f}; \end{screen} In the graphical interface this will display as \begin{equation*} \ftableau{a b c, d e, f} \end{equation*} See \subsprop{Tableau} for information about adding the dimension of the permutation group. cadabra-1.39/doc/properties/GammaMatrix.tex000066400000000000000000000011421234107666300207230ustar00rootroot00000000000000\cdbproperty{GammaMatrix}{\it metric={\sf metric name}} A generalised generator of a Clifford algebra. With one vector index, it satisfies \begin{equation} \{ \Gamma^m, \Gamma^n \} = 2\,\eta^{mn}\,. \end{equation} The objects with more vector indices are defined as \begin{equation} \Gamma^{m_1\ldots m_n} = \Gamma^{[m_1}\cdots \Gamma^{m_n]}\,, \end{equation} where the anti-symmetrisation includes a division by~$n!$. If you intend to use the \subscommand{join} algorithm, you have to add a key/value pair \verb|metric| to set the name of the tensor which acts as the unit element in the Clifford algebra. cadabra-1.39/doc/properties/GammaTraceless.tex000066400000000000000000000002031234107666300214010ustar00rootroot00000000000000\cdbproperty{GammaTraceless}{} Declares a spinor object with a vector index to be zero when it is contracted with a gamma matrix. cadabra-1.39/doc/properties/ImplicitIndex.tex000066400000000000000000000010551234107666300212610ustar00rootroot00000000000000\cdbproperty{ImplicitIndex}{} Indicates that the object carries implicit indices, e.g.~for objects representing matrices or vectors. Such objects will not be moved through each other, i.e.~they are mutually noncommuting. \begin{screen}{1,2,3} {M,A}::ImplicitIndex; M A; @prodsort!(%); M A; \end{screen} Without the \subsprop{ImplicitIndex} property, \subscommand{prodsort} would have freely moved the objects through each other. For more information on how to use matrices and vectors with implicit indices, see \subscommand{expand}. \cdbseealgo{expand} cadabra-1.39/doc/properties/IndexInherit.tex000066400000000000000000000013061234107666300211100ustar00rootroot00000000000000\cdbproperty{IndexInherit}{} Indicates that an object should inherit the indices of its child objects. This is useful mainly for operators. Matrix transposition, for instance, could be written as \begin{screen}{1,2,3} T{#}::IndexInherit. T(B_{m n}) + C_{m n}; \end{screen} Without the \subsprop{IndexInherit} property, the object \verb|T(B_{m n})| would be considered a scalar, without indices, and an index mismatch error would be reported. With the property, the first term has external indices \verb|m| and \verb|n|, just like the second term. This property is automatically associated to all \subsprop{Derivative} operators. \cdbseeprop{Indices} \cdbseeprop{Derivative} \cdbseeprop{PartialDerivative} cadabra-1.39/doc/properties/Indices.tex000066400000000000000000000033151234107666300200760ustar00rootroot00000000000000\cdbproperty{Indices}{\it name={\sf set name}, parent={\sf parent set name}, position=free$\vert$fixed$\vert$independent} Declare index names to be usable for dummy index purposes. Typical usage is of the form \begin{screen}{1,2} {r,s,t}::Indices(vector). {a,b,c,d}::Indices(spinor). \end{screen} This indicates the name of the index set (``vector'' resp.~``spinor'' in the example above). Indices can occur as subscripts or superscripts, and you may use this to indicate e.g.~covariant and contravariant transformation behaviour. In this case, use the additional argument \verb|position=fixed| to indicate that the position carries meaning. If you do not want cadabra to automatically raise or lower indices when canonicalising expressions, or if upper and lower indices are not related at all, use \verb|position=independent|. When you work with vector spaces which are subspaces of larger spaces, it is possible to indicate that a given set of indices take values in a subset of values of a larger set. An example makes this more clear. Suppose we have one set of indices~$A,B,C$ which take values in a four-dimensional space, and another set of indices~$a,b,c$ which take values in a three-dimensional subspace. This is declared as \begin{screen}{1,2} {A,B,C}::Indices(fourD). {a,b,c}::Indices(threeD, parent=fourD). \end{screen} This will allow cadabra to canonicalise expressions which contain mixed index types, as in \begin{screen}{1,2,3,4,5,6} {A,B,C}::Indices(fourD). {a,b,c}::Indices(threeD, parent=fourD). M_{q? r?}::AntiSymmetric. M_{a A} + M_{A a}: @canonicalise!(%): @collect_terms!(%); 0; \end{screen} Note the way in which the symmetry of the~$M$ tensor was declared here. \cdbseealgo{split_index} \cdbseeprop{Integer} cadabra-1.39/doc/properties/Integer.tex000066400000000000000000000005641234107666300201200ustar00rootroot00000000000000\cdbproperty{Integer}{\sf range} Indicates that the object takes values in the integers. An optional range can be specified, \begin{screen}{1,2,3} p::Integer; m::Integer(1..10); n::Integer(1..d-p); \end{screen} This property is often used in combination with the \subsprop{Indices} property to indicate the range of numbers over which indices run. \cdbseeprop{Indices} cadabra-1.39/doc/properties/InverseMetric.tex000066400000000000000000000006751234107666300213050ustar00rootroot00000000000000\cdbproperty{InverseMetric}{} This property is the partner of \subsprop{Metric}. It makes the associated two-tensor symmetric and also indicates that it can be used to raise or lower indices. \begin{screen}{1,2,3} g^{m n}::InverseMetric. g_{m n}::Metric. g_{m q} g^{m n} A_{n p}; @eliminate_metric!(%); A_{q p}; \end{screen} For more information, see \subsprop{Metric}. \cdbseealgo{eliminate_metric} \cdbseeprop{Metric} \cdbseeprop{Symmetric} cadabra-1.39/doc/properties/InverseVielbein.tex000066400000000000000000000003361234107666300216110ustar00rootroot00000000000000\cdbproperty{InverseVielbein}{} The partner of \subsprop{Vielbein}. See the \subscommand{eliminate\_vielbein} command for more information on typical usage patterns. \cdbseeprop{Vielbein} \cdbseealgo{eliminate_vielbein} cadabra-1.39/doc/properties/KeepHistory.tex000066400000000000000000000010661234107666300207670ustar00rootroot00000000000000\cdbproperty{KeepHistory}{} This is a global property. When set to false, only the last version of each expression is kept in memory, thereby reducing memory usage for very large expressions. The default is ``true''. When set to ``false'', \subscommand{pop} is no longer available to return to previous forms of the expression: \begin{screen}{1,2,3,4} ::KeepHistory(false). (a+b)*(c+d); @distribute!(%); @pop(%); @pop: not applicable. \end{screen} In general this is only useful to conserve memory when extremely long expressions are manipulated. \cdbseealgo{pop} cadabra-1.39/doc/properties/KroneckerDelta.tex000066400000000000000000000014441234107666300214160ustar00rootroot00000000000000\cdbproperty{KroneckerDelta}{} Denotes a generalised Kronecker delta symbol. When the symbol carries two indices, it is the usual Kronecker delta. When the number of indices is larger, the meaning is \begin{equation} \delta_{m_1}{}^{n_1}{}_{m_2}{}^{n_2}{}_{\ldots m_k}{}^{n_k} = \delta_{[m 1}{}^{n_1} \delta_{m_2}{}^{n_2} \cdots \delta_{m_k]}{}^{n_k} \,, \end{equation} with unit weight anti-symmetrisation. A symbol which is declared as a Kronecker delta has the property that it can be taken in and out of derivatives. The algorithm \subscommand{eliminate\_kr} eliminates normal Kronecker deltas by appropriately renaming indices (in order to eliminate Kronecker deltas with more than two indices, first use \subscommand{breakgendelta}). \cdbseealgo{eliminate_kr} \cdbseealgo{breakgendelta} cadabra-1.39/doc/properties/LaTeXForm.tex000066400000000000000000000017661234107666300203310ustar00rootroot00000000000000\cdbproperty{LaTeXForm}{\sf valid \LaTeX{} expression} Changes the way in which symbols are displayed in the graphical interface. Example: \begin{screen}{1,2} \del{#}::LaTeXForm("\partial"). \del_{m}(A); \end{screen} This prints $\partial_{m}(A);$ in the notebook, despite the fact that \verb|\del| is not a \LaTeX{} command. If you use this property to make a symbol printable, make sure to declare it \emph{before} any other properties are declared, otherwise the notebook will not know how to display the symbol and produce an error message. Note that the property is attached to a pattern (\verb|\del{#}| in this case) which matches the expression in which the replacement has to be made. If the pattern matches, the replacement will be done on the head symbol (\verb|\del| in this case). A pattern \verb|\del| without the argument wildcard \verb|#| would only replace when \verb|\del| occurs without any arguments (as in e.g.~\verb|\del + A|). These settings have no effect in the command-line version. cadabra-1.39/doc/properties/Matrix.tex000066400000000000000000000011421234107666300177600ustar00rootroot00000000000000\cdbproperty{Matrix}{} Declares an object to have two implicit indices, thus making it a matrix object. This is useful in combination with the index bracket notation. Example: \begin{screen}{1,2} {m,n,p,q}::Indices. A::Matrix. V::ImplicitIndex. (A V)_{m}; @expand!(%); A_{m n} V_{n}; \end{screen} Objects with the \subsprop{Matrix} property automatically become non-commuting among themselves, but retain their commutativity properties with other objects. \begin{screen}{1,2} {A,C}::Matrix. A C B A; @prodsort!(%); A B C A; \end{screen} ~ \cdbseealgo{prodsort} \cdbseealgo{Spinor} \cdbseeprop{ImplicitIndex} cadabra-1.39/doc/properties/Metric.tex000066400000000000000000000007261234107666300177460ustar00rootroot00000000000000\cdbproperty{Metric}{{\it signature={\sf integer}}} Labels the object as a symmetric tensor, and optionally gives it the indicated signature through the {\tt signature} parameter. \begin{screen}{1,2,3} g_{m n}::Metric(signature=1). g_{m n} A^{n p}; @eliminate_metric!(%); A_{m}^{p}; \end{screen} Objects declared as \subsprop{Metrics} can be used to automatically raise or lower indices using the \subscommand{eliminate\_metric} command. \cdbseealgo{eliminate_metric} cadabra-1.39/doc/properties/NonCommuting.tex000066400000000000000000000003721234107666300211350ustar00rootroot00000000000000\cdbproperty{NonCommuting}{} Makes components non-commuting. See \subsprop{AntiCommuting} for more information on commutativity properties. \cdbseeprop{AntiCommuting} \cdbseeprop{SelfAntiCommuting} \cdbseeprop{Commuting} \cdbseeprop{ImplicitIndex} cadabra-1.39/doc/properties/NumericalFlat.tex000066400000000000000000000005061234107666300212450ustar00rootroot00000000000000\cdbproperty{NumericalFlat}{} Indicates that an operator is such that numerical factors can be taken out of its argument. \begin{screen}{1,2} Q{#}::NumericalFlat. Q( 3 A ) + R( 3 A ); @numerical_flatten!(%); 3 Q( A ) + R( 3 A ); \end{screen} ~ \cdbseeprop{Derivative} \cdbseealgo{numerical_flatten} \cdbseealgo{listflatten} cadabra-1.39/doc/properties/PartialDerivative.tex000066400000000000000000000016421234107666300221400ustar00rootroot00000000000000\cdbproperty{PartialDerivative}{} Makes an object a partial derivative, i.e.~a derivative which commutes. The object on which it acts has to be a non-sub/superscript child, while all the sub- or superscript child nodes are interpreted to be the variables with respect to which the derivative is taken. \begin{screen}{1,2,3,4} \partial{#}::PartialDerivative. A_{\mu}::Depends(\partial). \partial_{\nu}{A_{\mu} B_{\rho}}; @prodrule!(%); \partial_{\nu}{A_\mu} B_{\rho} \end{screen} Note that derivative objects do not necessarily need to have a sub- or superscript child, they can be abstract derivatives as in \begin{screen}{1,2,3} D(d?)::PartialDerivative. D(c d e); @prodrule!(%); D(c) d e + c D(d) e + c d D(e); \end{screen} If you want to write a derivative with respect to a coordinate (instead of with respect to an index, as in the first example above), refer to the \subsprop{Coordinate} property. \cdbseeprop{Coordinate} cadabra-1.39/doc/properties/PostDefaultRules.tex000066400000000000000000000011651234107666300217660ustar00rootroot00000000000000\cdbproperty{PostDefaultRules}{} Set the default rules, to be applied \emph{after} every new input has been processed and active nodes have been executed. Use the inert form of active nodes for those ones that only have to be come active upon actual evaluation of the rule, i.e.~\inertcommand{collect\_terms!(\%)}. Here is an example containing more than one rule: \begin{screen}{1,2} ::PostDefaultRules( @@distribute!(%), @@prodsort!(%), @@collect_terms!(%) ). A*(B+C) + B*(A+C); 2 A B + A C + B C; \end{screen} Note that the rules have to be given in order; the list will only be traversed once. \cdbseeprop{PreDefaultRules} cadabra-1.39/doc/properties/PreDefaultRules.tex000066400000000000000000000002571234107666300215700ustar00rootroot00000000000000\cdbproperty{PreDefaultRules}{} Set the default rules to be executed on all input \emph{before} the active nodes in that input are expanded. \cdbseeprop{PostDefaultRules} cadabra-1.39/doc/properties/PropertyInherit.tex000066400000000000000000000003651234107666300216710ustar00rootroot00000000000000\cdbproperty{PropertyInherit}{} Indicates that an object should inherit all properties of the objects they wrap. In most cases, the use of \subsprop{Accent} is more appropriate, since it also makes objects inherit indices. \cdbseeprop{Accent} cadabra-1.39/doc/properties/RiemannTensor.tex000066400000000000000000000005751234107666300213110ustar00rootroot00000000000000\cdbproperty{RiemannTensor}{} Gives an object the symmetry properties of a Riemann tensor. \begin{screen}{1,2} R_{m n p q}::RiemannTensor; A^{m n p}::AntiSymmetric. A^{m n p} R_{m n p q}; @impose_bianchi!(%); 0; \end{screen} Various other algorithms, such as \subscommand{canonicalise}, also take into account this property. \cdbseealgo{canonicalise} \cdbseealgo{impose_bianchi} cadabra-1.39/doc/properties/SatisfiesBianchi.tex000066400000000000000000000011521234107666300217250ustar00rootroot00000000000000\cdbproperty{SatisfiesBianchi}{} Indicates that an object satisfies a (generalised) Bianchi identity. This is often used to link a derivative operator to a curvature tensor, as in \begin{screen}{1,2,3,4,5,6,8} R_{m n p q}::RiemannTensor; D{#}::Derivative. D_{m}{ R_{n p q r} }::SatisfiesBianchi. A^{m n p q}::AntiSymmetric. D_{m}{ R_{n p q r} } A^{m n p q}; @canonicalise!(%); (-1) D_{m}{ R_{r n p q} } A^{m n p q}; @impose_bianchi!(%); 0; \end{screen} This general method allows one to handle more than one type of derivative object. \cdbseeprop{RiemannTensor} \cdbseealgo{canonicalise} \cdbseealgo{impose_bianchi} cadabra-1.39/doc/properties/SelfAntiCommuting.tex000066400000000000000000000007421234107666300221110ustar00rootroot00000000000000\cdbproperty{SelfAntiCommuting}{} Used to make objects with indices anti-commuting when their index values are different. Example: \begin{screen}{1,2,3,5,6} \psi^{\mu}::SelfAntiCommuting. \psi^{\nu} \psi^{\mu}: @prodsort!(%); (-1) \psi^{\mu} \psi^{\nu}; \psi^{\mu} \psi^{\mu}: @canonicalise!(%); 0; \end{screen} This could not be handled with \subsprop{AntiCommuting} because that property handles the behaviour of \emph{different} expression patterns. \cdbseealgo{AntiCommuting} cadabra-1.39/doc/properties/SelfCommuting.tex000066400000000000000000000003651234107666300212760ustar00rootroot00000000000000\cdbproperty{SelfCommuting}{} Used to make objects with indices commuting when their index values are different. This is the default, so usually not needed. See \subsprop{SelfAntiCommuting} for more information. \cdbseealgo{SelfAntiCommuting} cadabra-1.39/doc/properties/SelfDual.tex000066400000000000000000000007531234107666300202220ustar00rootroot00000000000000\cdbproperty{SelfDual}{} Make a tensor fully anti-symmetric as well as self-dual. The conventions used are that self-duality means \begin{equation} F_{\mu_1\cdots \mu_n} = \frac{1}{n!} \epsilon_{\mu_1\cdots\mu_n \mu_{n+1}\cdots \mu_{2n}} F_{\mu_{n+1}\cdots\mu_{2n}}\,. \end{equation} This property used by the Young projection algorithms and the \subscommand{dualise\_tensor} algorithm, among others. \cdbseeprop{AntiSelfDual} \cdbseealgo{dualise_tensor} \cdbseealgo{young_project_tensor} cadabra-1.39/doc/properties/SelfNonCommuting.tex000066400000000000000000000003201234107666300217400ustar00rootroot00000000000000\cdbproperty{SelfNonCommuting}{} Used to make objects with indices non-commuting when their index values are different. See \subsprop{SelfAntiCommuting} for more information. \cdbseealgo{SelfAntiCommuting} cadabra-1.39/doc/properties/SigmaBarMatrix.tex000066400000000000000000000001421234107666300213650ustar00rootroot00000000000000\cdbproperty{SigmaBarMatrix}{} See \subsprop{SigmaMatrix} for details. \cdbseeprop{SigmaMatrix} cadabra-1.39/doc/properties/SigmaMatrix.tex000066400000000000000000000017211234107666300207440ustar00rootroot00000000000000\cdbproperty{SigmaMatrix}{} These are the invariant tensors relating the~$(\tfrac{1}{2},\tfrac{1}{2})$ to the vector representation of SO(3,1). \Cdb uses the Wess~\& Bagger conventions, which means that the metric has signature~$\eta = {\rm diag}(-1,1,1,1)$ and \begin{equation} (\sigma^{\mu})_{\alpha\dot{\beta}} = ( -{\mathbb 1}, \vec\sigma )_{\alpha\dot{\beta}}\,,\quad (\bar{\sigma}^{\mu})^{\dot{\alpha}\beta} = (-{\mathbb 1}, -\vec\sigma)^{\dot{\alpha}\beta}\,. \end{equation} When the objects carry two vector indices, they are understood to be \begin{equation} (\sigma^{m n})_{\alpha}{}^{\beta} \equiv \frac{1}{4}( \sigma^m \bar{\sigma}^n - \sigma^n \bar{\sigma}^m)_{\alpha}{}^{\beta}\,,\quad\quad (\bar{\sigma}^{m n})^{\dot{\alpha}}{}_{\dot{\beta}} \equiv \frac{1}{4}(\bar{\sigma}^m \sigma^{n} - \bar{\sigma}^n \sigma^{m})^{\dot{\alpha}}{}_{\dot{\beta}}\,. \end{equation} See below for algorithms dealing with the conversion from indexed to index-free notation. cadabra-1.39/doc/properties/SortOrder.tex000066400000000000000000000005251234107666300204430ustar00rootroot00000000000000\cdbproperty{SortOrder}{} A list property which determines the preferred order of objects when a \subscommand{prodsort} command is used. \begin{screen}{1,2} {B,A,C,A_{m}}::SortOrder. A A_{m} B C; @prodsort!(%); B A C A_{m}; \end{screen} As indicated in the example above, any type of object can appear in the list. \cdbseealgo{prodsort} cadabra-1.39/doc/properties/Spinor.tex000066400000000000000000000015641234107666300177760ustar00rootroot00000000000000\cdbproperty{Spinor}{\it dimension={\sf integer}, type=Weyl$\vert$Majorana$\vert$MajoranaWeyl, chirality=Positive$\vert$Negative} Declares an object to be a spinor, i.e.~transforming in one of the spinor representations of the orthogonal or Lorentz group. The declaration should involve an indication of the dimension, as in the example below. It can optionally have type indicators (these should be {\tt Majorana}, {\tt Weyl} or {\tt MajoranaWeyl}) and chirality indicators for Weyl spinors ({\tt Positive} or {\tt Negative}, indicating the eigenvalue with respect to the generalised~$\gamma_5$ matrix). Here is an example: \begin{screen}{1,2} \psi::Spinor(dimension=11, type=Majorana). \end{screen} This property is taken into account by various algorithms such as \subscommand{fierz} and \subscommand{spinorsort}. \cdbseeprop{DiracBar} \cdbseealgo{fierz} \cdbseealgo{spinorsort} cadabra-1.39/doc/properties/Symbol.tex000066400000000000000000000010251234107666300177610ustar00rootroot00000000000000\cdbproperty{Symbol}{} If you want to attach symbols to tensors in sub- or superscript, as in~$A^\dagger$, you need to inform the system that this symbol is not an index (otherwise it may interpret~$A^\dagger A^\dagger$ as two contracted vectors with vector indices~$\dagger$). This is done by associating the \subsprop{Symbol} property to the symbol; in this example \begin{screen}{1,2} \dagger::Symbol. A^\dagger A^\dagger; \end{screen} A related effect is induced by the \subsprop{Coordinate} property. \cdbseeprop{Coordinate} cadabra-1.39/doc/properties/Symmetric.tex000066400000000000000000000003031234107666300204660ustar00rootroot00000000000000\cdbproperty{Symmetric}{} Makes an object symmetric in all its indices. For an example and more information, see \subsprop{AntiSymmetric}. \cdbseeprop{AntiSymmetric} \cdbseealgo{canonicalise} cadabra-1.39/doc/properties/Tableau.tex000066400000000000000000000011461234107666300200750ustar00rootroot00000000000000\cdbproperty{Tableau}{\it dimension={\sf integer}} Indicates that the object is a Young diagram, i.e.~a tableau without labels in the boxes. The arguments of a \subsprop{Tableau} property denote the lengths of the successive rows, \begin{screen}{1,2} \tab{#}::Tableau. \tab{4}{2}{1}; \end{screen} In the graphical interface this will display as \begin{equation*} \tableau{4 2 1} \end{equation*} For several algorithms, the dimension of the permutation group associated to the tableau must be known; this can be added as in the example below, \begin{screen}{1} \tab{#}::Tableau(dimension=10). \end{screen} ~ cadabra-1.39/doc/properties/TableauSymmetry.tex000066400000000000000000000010571234107666300216500ustar00rootroot00000000000000\cdbproperty{TableauSymmetry}{\it shape={\sf tableau shape}, indices={\sf index positions}, selfdual, antiselfdual} Takes lists of two key-value pairs as arguments, indicating the shape of the Young tableau and the index slots associated to each box in the tableau. For instance \begin{screen}{1} R_{a b c d}::TableauSymmetry( shape={2,2}, indices={0,2,1,3} ). \end{screen} yields the symmetries of the Riemann tensor. Note that indices are counted from zero. It is also possible to label tensors as self-dual or anti-selfdual using the optional arguments. cadabra-1.39/doc/properties/Traceless.tex000066400000000000000000000003621234107666300204440ustar00rootroot00000000000000\cdbproperty{Traceless}{} Indicates that the tensor is traceless: any internal index contraction makes the tensor vanish. \begin{screen}{1,2,3} A_{m n}::Traceless. A_{m}^{m}; @canonicalise!(%); 0; \end{screen} ~ \cdbseealgo{canonicalise} cadabra-1.39/doc/properties/Vielbein.tex000066400000000000000000000003501234107666300202510ustar00rootroot00000000000000\cdbproperty{Vielbein}{} Indicates that an object can be used to convert indices from one type to another, i.e.~is a vielbein or tetrad. For more information, see \subscommand{eliminate\_vielbein}. \cdbseealgo{eliminate_vielbein} cadabra-1.39/doc/properties/Weight.tex000066400000000000000000000005011234107666300177410ustar00rootroot00000000000000\cdbproperty{Weight}{\it label={\sf name}, value={\sf rational}} Attach a labelled weight to an object, which can subsequently be used in the algorithms \subscommand{keep\_weight} and \subscommand{drop\_weight}. See the documentation of those algorithms for examples. \cdbseealgo{keep_weight} \cdbseealgo{drop_weight} cadabra-1.39/doc/properties/WeightInherit.tex000066400000000000000000000030151234107666300212670ustar00rootroot00000000000000\cdbproperty{WeightInherit}{\it label={\sf name}$\vert$all, type=Additive$\vert$Multiplicative, self={\sf value}} Indicates that the object inherits all weights of its child nodes. The label indicates which weights are inherited; use {\tt all} to inherit all weights. The type of inheritance determines whether weights of the child nodes should be added or multiplied. Additive weight inheritance is used to assign a weight to sum-like objects. For example, if we declare \begin{screen}{0,1} f{#}::WeightInherit(label=all, type=Additive). A::Weight(label=field, value=3). \end{screen} then the expression~\verb|f{A}{A}| has weight~3. This is what would happen if `\verb|f|' would be a sum: the weight of the sum is the same as the weight of the terms (and is only defined if the weight of the all terms is equal). Multiplicative weight inheritance is used to assign a weight to product-like objects. For example, if we declare \begin{screen}{0,1,2} f{#}::WeightInherit(label=all, type=Multiplicative). A::Weight(label=field, value=3). \end{screen} then the expression~\verb|f{A}{A}| has weight~6. This is what would happen if `\verb|f|' would be a product: the weight of the product is the same as the sum of the weights of the factors. Terms can be selected based on their weight by using the \subscommand{keep\_weight} and \subscommand{drop\_weight} algorithms. For more information on related topics, see \subsprop{IndexInherit} and \subsprop{PropertyInherit}. \cdbseeprop{Weight} \cdbseeprop{PropertyInherit} \cdbseeprop{IndexInherit} cadabra-1.39/doc/properties/WeylTensor.tex000066400000000000000000000003451234107666300206330ustar00rootroot00000000000000\cdbproperty{WeylTensor}{} Gives an object the symmetry properties of a Weyl tensor, i.e.~a Riemann tensor with an additional traceless condition. For more information, see \subsprop{RiemannTensor}. \cdbseeprop{RiemannTensor} cadabra-1.39/doc/reserved/000077500000000000000000000000001234107666300154175ustar00rootroot00000000000000cadabra-1.39/doc/reserved/anticommutator.tex000066400000000000000000000003501234107666300212050ustar00rootroot00000000000000\cdbreserved{anticommutator}{} Denotes the anti-commutator of two objects. The default properties of \verb|\anticommutator| are \begin{verbatim} \anticommutator{#}::IndexInherit. \anticommutator{#}::Derivative. \end{verbatim} cadabra-1.39/doc/reserved/arrow.tex000066400000000000000000000000651234107666300172740ustar00rootroot00000000000000\cdbreserved{arrow}{} Denotes a substitution rule. cadabra-1.39/doc/reserved/cdot.tex000066400000000000000000000002041234107666300170660ustar00rootroot00000000000000\cdbreserved{cdot}{} Denotes a dot product of vectors in which the contracted indices are suppressed. Displays as an infix dot. cadabra-1.39/doc/reserved/comma.tex000066400000000000000000000002521234107666300172340ustar00rootroot00000000000000\cdbreserved{comma}{} Denotes comma-separated objects. The parser rewrites any set of objects which are separated by an infix comma using the \verb|\comma| object. cadabra-1.39/doc/reserved/commutator.tex000066400000000000000000000003231234107666300203310ustar00rootroot00000000000000\cdbreserved{commutator}{} Denotes the commutator of two objects. The default properties of \verb|\commutator| are \begin{verbatim} \commutator{#}::IndexInherit. \commutator{#}::Derivative. \end{verbatim} cadabra-1.39/doc/reserved/conditional.tex000066400000000000000000000004071234107666300204450ustar00rootroot00000000000000\cdbreserved{conditional}{} Denotes a conditional pattern. The parser rewrites an infix vertical bar operator using a \verb|\conditional| object, in which the first argument is the pattern and the second argument is the condition under which the pattern holds. cadabra-1.39/doc/reserved/equals.tex000066400000000000000000000001761234107666300174370ustar00rootroot00000000000000\cdbreserved{equals}{} Denotes equalities. The parser rewrites an infix \verb|=| operator using an \verb|\equals| object. cadabra-1.39/doc/reserved/expression.tex000066400000000000000000000001121234107666300203320ustar00rootroot00000000000000\cdbreserved{expression}{} Denotes the top-level node of an expression. cadabra-1.39/doc/reserved/factorial.tex000066400000000000000000000002211234107666300201000ustar00rootroot00000000000000\cdbreserved{factorial}{} Denotes the factorial of an object. The parser rewrites a post-fix exclamation mark as a \verb|\factorial| object. cadabra-1.39/doc/reserved/frac.tex000066400000000000000000000000731234107666300170540ustar00rootroot00000000000000\cdbreserved{frac}{} Denotes a generic ratio of objects. cadabra-1.39/doc/reserved/indexbracket.tex000066400000000000000000000004411234107666300206030ustar00rootroot00000000000000\cdbreserved{indexbracket}{} Denotes a group of objects with indices which are collectively written, as in~\mbox{$(A + B + C)_{m n}$}. The default properties of \verb|\indexbracket| are \begin{verbatim} \indexbracket{#}::Distributable. \indexbracket{#}::IndexInherit. \end{verbatim} ~ cadabra-1.39/doc/reserved/infty.tex000066400000000000000000000000541234107666300172710ustar00rootroot00000000000000\cdbreserved{infty}{} Denotes infinity. cadabra-1.39/doc/reserved/label.tex000066400000000000000000000000761234107666300172230ustar00rootroot00000000000000\cdbreserved{label}{} Denotes the label of an expression. cadabra-1.39/doc/reserved/pow.tex000066400000000000000000000004141234107666300167450ustar00rootroot00000000000000\cdbreserved{pow}{} Denotes a generic exponent of one object raised to the power of another object. The parser translates the infix ``\verb|**|'' to \verb|\pow|. The default properties of \verb|\prod| are \begin{verbatim} \pow{#}::DependsInherit. \end{verbatim} ~ cadabra-1.39/doc/reserved/prod.tex000066400000000000000000000007611234107666300171110ustar00rootroot00000000000000\cdbreserved{prod}{} Denotes a generic product of objects. The parser translates objects separated by whitespace or by a ``\verb|*|'' symbol to products. The default properties of \verb|\prod| are \begin{verbatim} \prod{#}::Distributable. \prod{#}::IndexInherit. \prod{#}::CommutingAsProduct. \prod{#}::DependsInherit. \prod{#}::WeightInherit(label=all, type=Multiplicative). \prod{#}::NumericalFlat. \end{verbatim} ~ \cdbseeprop{AntiCommuting} \cdbseeprop{NonCommuting} \cdbseealgo{prodsort} cadabra-1.39/doc/reserved/regex.tex000066400000000000000000000002511234107666300172510ustar00rootroot00000000000000\cdbreserved{regex}{} Denotes a regular expression name pattern. The first argument is a symbol and the second argument is a string containing the regular expression. cadabra-1.39/doc/reserved/sequence.tex000066400000000000000000000002411234107666300177460ustar00rootroot00000000000000\cdbreserved{sequence}{} Denotes a sequence or range of objects. The parser rewrites an infix \verb|..| operator (two dots) using a \verb|\sequence| object. cadabra-1.39/doc/reserved/sum.tex000066400000000000000000000005341234107666300167470ustar00rootroot00000000000000\cdbreserved{sum}{} Denotes a generic sum of objects. The parser translates objects separated by a ``$+$'' symbol tol sums. The default properties of \verb|\sum| are \begin{verbatim} \sum{#}::CommutingAsSum. \sum{#}::DependsInherit. \sum{#}::IndexInherit. \sum{#}::WeightInherit(label=all, type=Additive). \end{verbatim} ~ \cdbseealgo{sumsort} cadabra-1.39/doc/reserved/unequals.tex000066400000000000000000000002051234107666300177730ustar00rootroot00000000000000\cdbreserved{unequals}{} Denotes inequalities. The parser rewrites an infix \verb|!=| operator using an \verb|\unequals| object. cadabra-1.39/doc/showcase.tex000066400000000000000000000164431234107666300161460ustar00rootroot00000000000000\documentclass{beamer} \usepackage{fancyvrb} \usepackage{xspace} \usefonttheme[onlymath]{serif} %------------------------------------------------------------------------------ \fvset{frame=lines,framerule=0.1pt,framesep=5pt,numbers=none,xleftmargin=0ex,fontfamily=tt,fontsize=\scriptsize} \newenvironment{screen}{\vspace{1ex}\Verbatim}{\endVerbatim\vspace{1ex}} \setbeamertemplate{navigation symbols}{} \setbeamersize{text margin right=2em} \setbeamersize{text margin left=2em} \newcommand{\Cpp}{{\leavevmode\rm{\hbox{C\hskip -0.1ex\raise 0.5ex\hbox{\tiny ++}}}}\xspace} \newcommand{\Blue}[1]{{\color[named]{Blue} #1}} %------------------------------------------------------------------------------ %------------------------------------------------------------------------------ % % Young tableau macro (taken from Distler & Zamora [hep-th/9810206]) % Usage: $\tableau{2 1 1}$ % \newdimen\tableauside\tableauside=1ex %1.0ex \newdimen\tableaurule\tableaurule=.32pt %0.4pt \newdimen\tableaustep \def\phantomhrule#1{\hbox{\vbox to0pt{\hrule height\tableaurule width#1\vss}}} \def\phantomvrule#1{\vbox{\hbox to0pt{\vrule width\tableaurule height#1\hss}}} \def\sqr{\vbox{% \phantomhrule\tableaustep \hbox{\phantomvrule\tableaustep\kern\tableaustep\phantomvrule\tableaustep}% \hbox{\vbox{\phantomhrule\tableauside}\kern-\tableaurule}}} \def\squares#1{\hbox{\count0=#1\noindent\loop\sqr \advance\count0 by-1 \ifnum\count0>0\repeat}} \def\tableau#1{\vcenter{\offinterlineskip \tableaustep=\tableauside\advance\tableaustep by-\tableaurule \kern\normallineskip\hbox {\kern\normallineskip\vbox {\gettableau#1 0 }% \kern\normallineskip\kern\tableaurule}% \kern\normallineskip\kern\tableaurule}} \def\gettableau#1 {\ifnum#1=0\let\next=\null\else \squares{#1}\let\next=\gettableau\fi\next} %------------------------------------------------------------------------------ % add: indexbracket % (\Gamma_{m n} - \Gamma_{m} * \Gamma_{n})_{\alpha\beta} \psi_{\beta} % (fails to input correctly!!!) % @join!(%); % add: generate basis -> LiE % add: variational derivatives: see substitute.cdb % {m,n,p,q,r,s}::Indices(vector). % A_{m n} A_{m p} B_{p n}; % @vary!(%)( A_{m n} -> varA_{m n} ); % @factorise is now tricky, do we need a separate other one? %------------------------------------------------------------------------------ \begin{document} \begin{frame}{Cadabra overview\hspace{.52\textwidth}\raisebox{.2ex}{\hbox{\small Kasper Peeters}}} \medskip \Blue{Features}: \begin{small}\begin{itemize}\setlength{\itemsep}{-2pt} \item Designed for ``field theory problems'' {\scriptsize (general~rel., quantum field~th., \ldots)}. \item Dummy index problems handled at internal storage level. \item Multiple spaces, multiple index types, implicit dependence: $T^{\alpha \dot{\beta}}_{m}(x)$ \ldots \item Commuting \& non-commuting tensors, user-specified sort order. \item All tensor symmetries handled (monoterm $\rightarrow$ {\tt xPerm} \& multi-term). \end{itemize}\end{small} \medskip \Blue{Interface}: \begin{small}\begin{itemize}\setlength{\itemsep}{-2pt} \item {\rm \TeX} input language. Command line \& TeXmacs frontend. \item Object behaviour specified by ``properties'' which can inherit. \item Conservative: no hidden algorithms unless the user enables them. \item Unlimited undo (optional). \end{itemize}\end{small} \medskip \Blue{Implementation}: \begin{small}\begin{itemize}\setlength{\itemsep}{-2pt} \item Standalone \Cpp, GPL license, no dependence on non-free tools. \item Preliminary: \url{http://www.aei.mpg.de/~peekas/cadabra/} \end{itemize}\end{small} \end{frame} %------------------------------------------------------------------------------ \begin{frame}{Example I: Multi-term symmetries} \begin{itemize} \item \Blue{Given}: basis for 4-th order Weyl tensor monomials \begin{small} \begin{equation*} \begin{aligned} W_1 &= W_{m n a b} W_{n p b c} W_{p s c d} W_{s m d a}\,,\quad W_2 = W_{m n a b} W_{n p b c} W_{m s c d} W_{s p d a}\,,\\[1ex] W_3 &= W_{m n a b} W_{p s b a} W_{m n c d} W_{p s d c}\,,\quad W_4 = W_{m n a b} W_{m n b a} W_{p s c d} W_{p s d c}\,,\\[1ex] W_5 &= W_{m n a b} W_{n p b a} W_{p s c d} W_{s m d c}\,,\quad W_6 = W_{m n a b} W_{p s b a} W_{m p c d} W_{n s d c}\,,\\[1ex] & \quad\quad\quad\quad W_7 = W_{m n}{}^{[m n} W_{p q}{}^{p q} W_{r s}{}^{r s} W_{t u}{}^{t u]}\,. \end{aligned} \end{equation*} \end{small} \medskip \item \Blue{Problem}: prove the identity \begin{equation*} W_{p q r s} W_{p t r u} W_{t v q w} W_{u v s w}- W_{p q r s} W_{p q t u} W_{r v t w} W_{s v u w} = W_2 - \tfrac{1}{4} W_6 \end{equation*} Relies on the cyclic Ricci identity. \medskip \item \Blue{Algorithm}: project each Weyl with its Young projector~$\tableau{2 2}$, canonicalise using mono-term symmetries, decompose. \end{itemize} \end{frame} %------------------------------------------------------------------------------ \begin{frame}[fragile] \frametitle{Example I: Multi-term symmetries} \begin{screen} {m,n,p,q,r,s,t,u,v,w,a,b,c,d,e,f}::Indices(vector). W_{m n p q}::WeylTensor. W1: W_{m n a b} W_{n p b c} W_{p s c d} W_{s m d a}; ... W7: W_{m n}^{m n} W_{p q}^{p q} W_{r s}^{r s} W_{t u}^{t u}; @asym!(%){^{m},^{n},^{p},^{q},^{r},^{s},^{t},^{u}}: @substitute!(%)( W_{a b}^{c d} -> W_{a b c d} ): @canonicalise!(%): basisW4: { @(W1), @(W2), @(W3), @(W4), @(W5), @(W6), @(W7) }; W_{p q r s} W_{p t r u} W_{t v q w} W_{u v s w} - W_{p q r s} W_{p q t u} W_{r v t w} W_{s v u w}; @decompose!(%){ @(basisW4) }; @list_sum!(%); \end{screen} \vspace{-3ex} \begin{screen} { 0, 1, 0, 0, 0, -1/4, 0 }; \end{screen} \end{frame} %------------------------------------------------------------------------------ \begin{frame}[fragile] \frametitle{Example II: Commuting \& non-commuting objects} \begin{itemize} \item Combinations of commuting and non-commuting tensors, e.g.~with~$\Gamma^m \psi_m = 0$ in 4d, \begin{equation*} \begin{aligned} \bar{\psi}_m (\Gamma_{m n} + A_{m} \Gamma_{n}) \Gamma_{p q r} \psi_{r} & = 6 \delta_{n p} \bar{\psi_{m}} \Gamma_{q} \psi_{m} - A_{m} \bar{\psi_{m}} \Gamma_{n p} \psi_{q} \\ & ~ + A_{m} \bar{\psi_{m}} \Gamma_{n q} \psi_{p} - A_{m} \bar{\psi_{m}} \Gamma_{p q} \psi_{n} \\ & ~ - 3 \delta_{n p} A_{m} \bar{\psi_{m}} \psi_{q}\,. \end{aligned} \end{equation*} \medskip \item Object properties: \begin{screen} {m,n,p,q,r}::Integer(0..3). \bar{#}::DiracBar. \Gamma{#}::GammaMatrix. \psi_{m}::Spinor(dimension=4). \psi_{m}::GammaTraceless. \delta_{m n}::KroneckerDelta. { \delta_{m n}, A_{m}, \psi_{m}, \Gamma_{#} }::SortOrder. \end{screen} \end{itemize} \end{frame} %------------------------------------------------------------------------------ \begin{frame}[fragile] \frametitle{Example II: Commuting \& non-commuting objects} \begin{itemize} \item The actual calculation (note the {\rm \TeX{}} input) \begin{screen} \bar{\psi_{m}} (\Gamma_{m n} + A_{m} \Gamma_{n}) \Gamma_{p q r} \psi_{r}; @distribute!(%); @join!(%); @distribute!(%); @prodsort!(%); @remove_gamma_trace!(%); @prodsort!(%); @remove_gamma_trace!(%); \end{screen} \medskip \item Output: \begin{screen} 6 \delta_{n p} * \bar{\psi_{m}} * \Gamma_{q} * \psi_{m} - A_{m} * \bar{\psi_{m}} * \Gamma_{n p} * \psi_{q} + A_{m} * \bar{\psi_{m}} * \Gamma_{n q} * \psi_{p} - A_{m} * \bar{\psi_{m}} * \Gamma_{p q} * \psi_{n} - 3 \delta_{n p} * A_{m} * \bar{\psi_{m}} * \psi_{q}; \end{screen} \end{itemize} \end{frame} \end{document} cadabra-1.39/doc/tree.html000066400000000000000000000304041234107666300154260ustar00rootroot00000000000000 tree.hh: an STL-like C++ tree class

tree.hh: an STL-like C++ tree class

Kasper Peeters, kasper.peeters (at) aei.mpg.de

(Impressed with this library? Do you want to hire me to develop other software? Contact me!)

Overview

The tree.hh library for C++ provides an STL-like container class for n-ary trees, templated over the data stored at the nodes. Various types of iterators are provided (post-order, pre-order, and others). Where possible the access methods are compatible with the STL or alternative algorithms are available. The library is available under the terms of the GNU General Public License version 2 or 3.
Documentation is available in the form of a postscript and a pdf file (also available in the tarball as a LaTeX file). This documentation is still a bit short and not entirely complete. See the test program (included in the distribution) for an example of how to use tree.hh. Also look at the simple example below. There is also some doxygen generated documentation.
The tree.hh code is available under the terms of the GNU General Public License 2 or 3. If you use tree.hh, please satisfy my curiosity and write me a small email with a bit of explanation of your software and the role of my tree class in it.
The tree.hh library is meant for generic n-ary trees. If you are only interested in AVL binary search trees (Adelson,Velskii & Landis), you may want to have a look at the C++ AVL tree template page.

Download

Everything (the header file, examples, documentation and all other things referred to on this page) is contained in the tarball
tree-VERSION.tar.gz
Feel free to copy the header tree.hh (which is all you need code-wise) into your own source directory as long as you respect the license (see above). The list of changes can be found in the ChangeLog.
See the intro above for links to the documentation. There is a very simple demonstration program available, tree_example.cc (also included in the tarball), which is discussed below. There is also a small test program, test_tree.cc, which makes use of the tree_util.hh utility functions by Linda Buisman; the output should be exactly identical to the test_tree.output file.
The current version works with GNU gcc 3.x and higher, Borland C++ builder and Microsoft Visual C++ 7.1 and higher. It is compatible with STLport.
Tony Cook has provided a version for the buggy Microsoft Visual C++ compilers up to version 7.0. You will have to use a special version of the header file, tree_msvc.hh (currently based on the original tree.hh version 1.80). The difference is that all members of the iterator and sibling_iterator subclasses have been moved inside the class definitions. If you get unresolved symbols in the linking phase, or other weird compiler errors, you should use this header. Microsoft users are urged to upgrade to version 7.1 which works with tree.hh out of the box.

Mailing list and update announcements

There is a mailing list for tree.hh, which is mostly used for announcements of new releases, but is also open for discussions about tree.hh which are of general interest. To subscribe, please visit the tree-hh mailing list web page.
I also announce major updates on Freshmeat though not as often as by email.

Projects using tree.hh

The tree.hh library is used in various projects:
Cadabra
A field-theory motivated approach to symbolic computer algebra.
Gnash
Gnash is a GNU Flash movie player. Previously, it was only possible to play flash movies with proprietary software. While there are some other free flash players, none support anything beyond SWF v4. Gnash is based on GameSWF, and supports many SWF v7 features.
Principles of Compiler Design
A course in compiler design at the Simon Fraser University, Canada.
liborigin
A library for reading OriginLab OPJ project files, which is used by QtiPlot and LabPlot, two applications for data analysis and visualisation.
EChem++
A project realizing the idea of a Problem Solving Environment (PSE) in the field of computational electrochemistry. Computer controlled experimental measurements, numerical simulation and analysis of electrochemical processes will be combined under a common user interface.
LZCS
A semistructured document transformation tool. LZCS compresses structured documents taking advantage of the redundant information that can appear in the structure. The main idea is that frequently repeated subtrees may exist and these can be replaced by a backward reference to their first occurance. See the accompanying paper for more details.
libOFX
A parser and an API designed to allow applications to very easily support OFX command responses, usually provided by financial institutions for statement downloads.
A genetic programming project
See this paper for more information.
FreeLing
The FreeLing package consists of a library providing language analysis services (such as morfological analysis, date recognition, PoS tagging, etc.)
Let me know about your project when you are using tree.hh, so that I can add it to the list.

Simple example

The following program constructs a tree of std::string nodes, puts some content in it and applies the find algorithm to find the node with content "two". It then prints the content of all the children of this node. You can download the source tree_example.cc if you're too lazy to type it in.
#include <algorithm>
#include <string>
#include <iostream>
#include "tree.hh"

using namespace std;

int main(int, char **)
   {
   tree<string> tr;
   tree<string>::iterator top, one, two, loc, banana;

   top=tr.begin();
   one=tr.insert(top, "one");
   two=tr.append_child(one, "two");
   tr.append_child(two, "apple");
   banana=tr.append_child(two, "banana");
   tr.append_child(banana,"cherry");
   tr.append_child(two, "peach");
   tr.append_child(one,"three");

   loc=find(tr.begin(), tr.end(), "two");
   if(loc!=tr.end()) {
      tree<string>::sibling_iterator sib=tr.begin(loc);
      while(sib!=tr.end(loc)) {
         cout << (*sib) << endl;
         ++sib;
         }
      cout << endl;
      tree<string>::iterator sib2=tr.begin(loc);
      tree<string>::iterator end2=tr.end(loc);
      while(sib2!=end2) {
         for(int i=0; i<tr.depth(sib2)-2; ++i) 
            cout << " ";
         cout << (*sib2) << endl;
         ++sib2;
         }
      }
   }
The output of this program is
apple
banana
peach

apple
banana
 cherry
peach
Note that this example only has one element at the top of the tree (in this case that is the node containing "one") but it is possible to have an arbitary number of such elements (then the tree is more like a "bush"). Observe the way in which the two types of iterators work. The first block of output, obtained using the sibling_iterator, only displays the children directly below "two". The second block iterates over all children at any depth below "two". In the second output block, the depth member has been used to determine the distance of a given node to the root of the tree.

Data structure

The data structure of the tree class is depicted below (see the documentation for more detailed information). Each node contains a pointer to the first and last child element, and each child contains pointers to its previous and next sibling:
           first_child        first_child 
 root_node-+----------node--+----->-------node
           |           |    |               |   
           |           |    |               V   next_sibling
           |           |    |               |
                       |    |             node
                       |    |               |
                       |    |               V   next_sibling
                       |    | last_child    |
                       |    +----->-------node
                       |                        
                       V next_sibling           
                       |                       
                       |     first_child                  
                      node--+----->-------node
                       |    |               |   
                       |    |               V   next_sibling
                       |    |               |
                       |    +-------------node
                       .
                       .
Iterators come in two types. The normal iterator iterates depth-first over all nodes. The beginning and end of the tree can be obtained by using the begin() and end() members. The other type of iterator only iterates over the nodes at one given depth (ie. over all siblings). One typically uses these iterators to iterate over all children of a node, in which case the [begin,end) range can be obtained by calling begin(iterator) and end(iterator).
Iterators can be converted from one type to the other; this includes the `end' iterators (all intervals are as usual closed at the beginning and open at the end).

free
		  hit counter
visitors so far cadabra-1.39/doc/tree.tex000066400000000000000000000353441234107666300152720ustar00rootroot00000000000000\documentclass[11pt]{kasper} % % If you do not have 'kasper.cls', see % http://www.damtp.cam.ac.uk/user/kp229/texstuff . \usepackage{makeidx} \usepackage{verbatim} \usepackage{relsize} \makeindex %\newcommand{\toindex}[1]{#1\index{#1}} \newcommand{\member}[1]{{\tt #1}\index{#1}} %\newcommand{\member}[1]{{\tt #1}} \def\mystrut{\vbox to 8.5pt{}\vtop to 3.5pt{}} \def\V{\hskip10pt\vrule\hskip10pt} \def\T{\hskip10pt\vrule\vrule height2.5pt depth -2.1pt width 10pt} \def\L{\hskip10pt\vrule height 8.5pt depth -2.1pt \vrule height2.5pt depth -2.1pt width 10pt} \def\N{\hskip10pt\phantom{\vrule}\hskip10pt} \def\hw{\hskip-1000pt plus 1fil} % to test: insert before end of subtree \begin{document} \title{{\tt tree.hh} documentation} \author{Kasper Peeters} \address{1}{{\it MPI/AEI f\"ur Gravitationsphysik, Am M\"uhlenberg 1, 14476 Potsdam, Germany}} \email{k.peeters@damtp.cam.ac.uk} \maketitle \begin{abstract} The {\tt tree.hh} library for C++ provides an STL-like container class for n-ary trees, templated over the data stored at the nodes. Various types of iterators are provided (post-order, pre-order, and others). Where possible the access methods are compatible with the STL or alternative algorithms are available. The library is available under the terms of the GNU General Public License.\\[3ex] Code and examples available at: {\tt http://www.damtp.cam.ac.uk/user/kp229/tree/}\\[3ex] {\bf This documentation is not yet complete. Refer to the {\tt tree.hh} header file for a full list of member functions.} \end{abstract} \maketoc \begin{sectionunit} \title{Overview} \maketitle \begin{sectionunit} \title{The container class} \maketitle The tree class of {\tt tree.hh} is a templated container class in the spirit of the STL. It organises data in the form of a so-called n-ary tree. This is a tree in which every node is connected to an arbitrary number of child nodes. Nodes at the same level of the tree are called ``siblings'', while nodes that are below a given node are called its ``children''. At the top of the tree, there is a set of nodes which are characterised by the fact that they do not have any parents. The collection of these nodes is called the ``head'' of the tree. See figure~\ref{f:overview} for a pictorial illustration of this structure (90 degrees rotated for convenience). \begin{figure}[th] \begin{center} \includegraphics[width=.5\textwidth]{treefig} \caption{Overview of the tree structure. The elements at the top of the tree (here displayed at the left for convenience) are in the ``head'' (there can be more than one such element). Every node is linked to its children using the ``first child'' and ``last child'' links. In addition, all nodes on a given level are doubly-linked using the ``previous sibling'' and ``next sibling'' links. The ``depth'' of a given node refers to the horizontal distance from the head nodes.} \label{f:overview} \end{center} \end{figure} The tree class is templated over the data objects stored at the nodes; just like you can have a {\tt vector} you can now have a {\tt tree}. Many STL algorithms work on this data structure, and where necessary alternatives have been provided. \medskip \end{sectionunit} \begin{sectionunit} \title{Iterators} \maketitle The essential difference between a container with the structure of a tree and the STL containers is that the latter are ``linear''. While the STL containers thus only have essentially one way in which one can iterate over their elements, this is not true for trees. The {\tt tree.hh} library provides (at present) four different iteration schemes. To describe them, consider the following tree: \begin{equation*} \vcenter{\offinterlineskip \halign{&#\mystrut\hfil\cr root \hw\cr \T A \cr \V \T B \cr \V \L C \cr \L D \cr \N \T E \cr \N \L F \cr}} \end{equation*} The three iteration types and the resulting order in which nodes are visited are tabulated below: \begin{center} \begin{tabular}{llll} pre-order (default) & ``element before children'' & \member{pre\_order\_iterator} & root A B C D E F \\ post-order & ``element after children'' & \member{post\_order\_iterator} & B C A E F D root \\ breadth-first & & \member{breadth\_first\_iterator} & root A D B C E F \\ sibling & ``only siblings'' & \member{sibling\_iterator} & (for ex.) A D \\ fixed-depth & & \member{fixed\_depth\_iterator} & (for ex.) A D \\ leaf & & \member{leaf\_iterator} & B C E F \end{tabular} \end{center} The pre-order ones are the default iterators, and therefore also known under the name of {\tt iterator}. Sibling iterators and fixed-depth iterators iterate only over the nodes at a given depth of the tree. The former restrict themselves to the child nodes of one given node, while the latter iterates over all child nodes at the given depth. Finally, leaf iterators iterate over all leafs (bottom-most) nodes of the tree. There are copy constructors that will convert iterators of the various types into each other. The post- and pre-order iterators are both also known as ``depth-first'', in contrast to the ``breadth-first'' iterator. The begin and end iterators of a tree can be obtained using \member{begin()} and \member{end()} (for pre-order iterators) or alternatively \member{begin\_post()} and \member{end\_post()} (for post-order iterators) and \member{begin\_leaf()} and \member{end\_leaf()} (for leaf iterators). Similarly, the begin and end sibling iterators can be obtained by calling \member{begin(iterator)} and \member{end(iterator)}. The range of children of a given node can also be obtained directly from an iterator, by using the {\tt iterator::begin()} and {\tt iterator::end()} member functions. If you want to (temporarily) make an iterator not go into the child subtree, call the member function \member{skip\_children}. This will only keep effect for a single increment or decrement of the iterator. Finally, whether or not an iterator is actually pointing at a node (i.e.~is not an ``end'' iterator) can be tested using the \member{is\_valid(iterator)} member of the tree class. \end{sectionunit} \end{sectionunit} \begin{sectionunit} \title{Basic operations} \maketitle \begin{description} \item[Initialising] There are two nontrivial constructors. One which takes a single node element as argument. It constructs a tree with this node begin the sole node in the head (in other words, it is a combination of a trivial constructor together with a \member{set\_head} call). The other non-trivial constructor takes an iterator, and copies the subtree starting at that node into the newly created tree (useful for constructing new tree objects given by subtrees of existing trees). \item[Tree traversal] Besides the \member{operator++} and \member{operator--} members for step-wise traversal through the tree, it is also possible to use the \member{operator+=} and \member{operator-=} member functions to make more than one step at the same time (though these are linear time, not amortized constant). The result of stepping beyond the end of the tree or stepping beyond the end of a sibling range (for sibling iterators) is undefined. The parent of a given node can be reached by calling the \member{parent} member of the tree object, giving it an iterator pointing to the node. If you know the number of children of a given node, you can get direct access to the $n$th child by using the \member{child} member function. Note that the value of the index is not checked and should therefore always be valid. \item[Appending child nodes] Nodes can be added as children of a given node using the \member{append\_child} member function. \item[Inserting nodes] Nodes can be inserted at the same depth as a given other node using the \member{insert} and \member{insert\_after} members functions. This is also how you insert the first node into a tree. \end{description} \end{sectionunit} \begin{sectionunit} \title{Other algorithms} \maketitle \begin{sectionunit} \title{Non-mutating algorithms} \maketitle \begin{description} \item[Counting nodes] The total number of nodes of a tree can be obtained using the \member{size} member function, while the number of children of a given node can be obtained with a call to \member{number\_of\_children(iterator)}. Similarly, the number of nodes at a given depth (the number of siblings of a given node) can be obtained using the \member{number\_of\_siblings} member function. \item[Determining depth] The \member{depth()} member function returns the distance of a node to the root. \item[Accessing siblings by their index] See the next item. \item[Determining index in a sibling range] In order to determine the index of a node in the range of siblings to which it belongs, use the \member{index(sibling\_iterator)} member function. The first sibling node has index 0. The reverse of this function (obtaining a sibling node given its index in the range of siblings) is called \member{child(const iterator\_base\&, unsigned int)}. \item[Comparing trees] While the STL \member{equal} algorithm can be used to compare the values of the nodes in two different trees, it does not know about the structure of the tree. If you want the comparison to take this into account, use the \member{equal(iterator, iterator, iterator, BinaryPredicate)} call of the tree class. As an addition to the STL algorithm, the length of the first range does not have to be equal to the length of the range pointed to by the second iterator. There is also an \member{equal\_subtree} algorithm which takes only two iterators, pointing to the (single-node) heads of two subtrees. \end{description} \end{sectionunit} \begin{sectionunit} \title{Mutating algorithms} \maketitle \begin{description} \item[Erasing nodes and subtrees] In order to remove a node including its children from the tree, use the \member{erase(iterator)} call. If you just want to erase the children, but not the node itself, use the \member{erase\_children(iterator)} call. \item[Replacing individual nodes or subtrees] \item[Flattening subtrees] The procedure of moving all children of a given node to be siblings of that node is called ``flattening''; it acts as \begin{equation*} \vcenter{\offinterlineskip \halign{&#\mystrut\hfil\cr apple \hw\cr \T banana\cr \V \T pear \cr \V \T strawberry \cr \V \L cherry \cr \L grape\cr}}\quad\rightarrow\quad \vcenter{\offinterlineskip \halign{&#\mystrut\hfil\cr apple \hw\cr \T banana\cr \T pear \cr \T strawberry \cr \T cherry \cr \L grape\cr}} \end{equation*} % \begin{screen} % apple apple % banana banana % pear -> pear % strawberry strawberry % cherry cherry % grape grape % \end{screen} when the tree is flattened at the ``banana'' node. \item[Moving or exchanging subtrees] Simple exchange of one sibling node with the next one is done through the member function \member{swap(sibling\_iterator)}. The iterator remains valid and remains pointing to the moved subtree. More complicated move operations are the \member{move\_ontop}, \member{move\_before} and \member{move\_after} ones. These all take two iterators, a source and a target. The member \member{move\_ontop(target, source)} removes the `target' node and all its children, and replaces it with the `source' node and its children. The `source' subtree is removed from its original location. The other two move members do a similar thing, differing only in the node which is to be replaced. \item[Extracting subtrees] You can create a new tree object filled with the data of a subtree of the original tree. This is analogous to the extraction of a substring of a string. The relevant member function is \member{subtree(sibling\_iterator, sibling\_iterator)} which takes a range of siblings as argument. There is also a slight variation of this member, which does not return a tree object but instead populates one that is passed as an argument (useful if you want to call this on a tree object subclassed from {\tt tree}. \item[Sorting] The standard STL sort algorithm is not very useful for trees, because it only exchanges values, not nodes. Applying it to a tree would mean that the structure of the tree remains unmodified, only node values get moved around (not their subtrees). Therefore, the {\tt tree} class has its own sort member. It comes in two forms, just like the STL sort, namely \begin{screen} void sort(sibling_iterator from, sibling_iterator to, bool deep=false); template void sort(sibling_iterator from, sibling_iterator to, StrictWeakOrdering comp, bool deep=false); \end{screen} The result of a call to either of these is that the nodes in the range described by the two iterators get sorted. If the boolean {\tt deep} is true, the subtrees of all these nodes will get sorted as well (and so one can sort the entire tree in one call). As in the STL, you can use the second form of this function to pass your own comparison class. If the nodes to which the two iterators point are not in the same sibling range (i.e.~not at the same depth in the tree), the result is undefined. \item[Merging] One way in which one might think of indicating the position where new nodes are to be inserted, is to give the path that leads to the insertion point. For instance, given the tree \begin{equation*} \vcenter{\offinterlineskip \halign{&#\mystrut\hfil\cr apple \hw\cr \T banana\cr \V \T pear \cr \V \T strawberry \cr \V \L cherry \cr \L grape\cr}} \end{equation*} one could imagine using the sub-tree \begin{equation*} \vcenter{\offinterlineskip \halign{&#\mystrut\hfil\cr apple \hw\cr \L banana\cr \N \T coconut \cr \N \L raspberry \cr}} \end{equation*} to indicate that the nodes ``coconut'' and ``raspberry'' are to be inserted as new children of the ``banana'' node. In {\tt tree.hh} this process is called \emph{tree merging}. It can do the simple addition of children as above, but actually handles the generic case too: as an example consider the merge \begin{equation*} \text{\tt merge}\left[ \vcenter{\offinterlineskip \halign{&#\mystrut\hfil\cr apple \hw\cr \T banana\cr \V \T pear \cr \V \T strawberry \cr \V \L cherry \cr \T grape\cr blueberry \cr}}\quad, \quad \vcenter{\offinterlineskip \halign{&#\mystrut\hfil\cr apple \hw\cr \T banana\cr \V \T coconut \cr \V \L raspberry \cr \T tangerine \cr \V \L plum\cr blueberry \cr \N \L orange \cr}}\right]\quad\rightarrow\quad \vcenter{\offinterlineskip \halign{&#\mystrut\hfil\cr apple \hw\cr \T banana\cr \V \T pear\cr \V \T strawberry\cr \V \T cherry\cr \V \T coconut \cr \V \L raspberry \cr \T grape\cr \T tangerine \cr \V \L plum\cr blueberry \cr \N \L orange \cr}} \end{equation*} As is clear from the above, the arguments to \member{merge} are two sibling ranges. \end{description} \end{sectionunit} \end{sectionunit} \printindex \end{document} cadabra-1.39/doc/treefig.eps000066400000000000000000000127221234107666300157420ustar00rootroot00000000000000%!PS-Adobe-2.0 EPSF-2.0 %%Title: tree.eps %%Creator: fig2dev Version 3.2 Patchlevel 0-beta3 %%CreationDate: Fri May 3 12:41:08 2002 %%For: kp229@church.amtp.cam.ac.uk (Kasper Peeters) %%Orientation: Portrait %%BoundingBox: 0 0 324 252 %%Pages: 0 %%BeginSetup %%EndSetup %%Magnification: 1.0000 %%EndComments /$F2psDict 200 dict def $F2psDict begin $F2psDict /mtrx matrix put /col-1 {0 setgray} bind def /col0 {0.000 0.000 0.000 srgb} bind def /col1 {0.000 0.000 1.000 srgb} bind def /col2 {0.000 1.000 0.000 srgb} bind def /col3 {0.000 1.000 1.000 srgb} bind def /col4 {1.000 0.000 0.000 srgb} bind def /col5 {1.000 0.000 1.000 srgb} bind def /col6 {1.000 1.000 0.000 srgb} bind def /col7 {1.000 1.000 1.000 srgb} bind def /col8 {0.000 0.000 0.560 srgb} bind def /col9 {0.000 0.000 0.690 srgb} bind def /col10 {0.000 0.000 0.820 srgb} bind def /col11 {0.530 0.810 1.000 srgb} bind def /col12 {0.000 0.560 0.000 srgb} bind def /col13 {0.000 0.690 0.000 srgb} bind def /col14 {0.000 0.820 0.000 srgb} bind def /col15 {0.000 0.560 0.560 srgb} bind def /col16 {0.000 0.690 0.690 srgb} bind def /col17 {0.000 0.820 0.820 srgb} bind def /col18 {0.560 0.000 0.000 srgb} bind def /col19 {0.690 0.000 0.000 srgb} bind def /col20 {0.820 0.000 0.000 srgb} bind def /col21 {0.560 0.000 0.560 srgb} bind def /col22 {0.690 0.000 0.690 srgb} bind def /col23 {0.820 0.000 0.820 srgb} bind def /col24 {0.500 0.190 0.000 srgb} bind def /col25 {0.630 0.250 0.000 srgb} bind def /col26 {0.750 0.380 0.000 srgb} bind def /col27 {1.000 0.500 0.500 srgb} bind def /col28 {1.000 0.630 0.630 srgb} bind def /col29 {1.000 0.750 0.750 srgb} bind def /col30 {1.000 0.880 0.880 srgb} bind def /col31 {1.000 0.840 0.000 srgb} bind def end save -126.0 342.0 translate 1 -1 scale /cp {closepath} bind def /ef {eofill} bind def /gr {grestore} bind def /gs {gsave} bind def /sa {save} bind def /rs {restore} bind def /l {lineto} bind def /m {moveto} bind def /rm {rmoveto} bind def /n {newpath} bind def /s {stroke} bind def /sh {show} bind def /slc {setlinecap} bind def /slj {setlinejoin} bind def /slw {setlinewidth} bind def /srgb {setrgbcolor} bind def /rot {rotate} bind def /sc {scale} bind def /sd {setdash} bind def /ff {findfont} bind def /sf {setfont} bind def /scf {scalefont} bind def /sw {stringwidth} bind def /tr {translate} bind def /tnt {dup dup currentrgbcolor 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb} bind def /shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul 4 -2 roll mul srgb} bind def /$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def /$F2psEnd {$F2psEnteredState restore end} def %%EndProlog $F2psBegin 10 setmiterlimit n -1000 6700 m -1000 -1000 l 8494 -1000 l 8494 6700 l cp clip 0.06000 0.06000 sc % Polyline 7.500 slw gs clippath 4380 3828 m 4350 3948 l 4320 3828 l 4320 3990 l 4380 3990 l cp 4320 3222 m 4350 3102 l 4380 3222 l 4380 3060 l 4320 3060 l cp clip n 4350 3075 m 4350 3975 l gs col0 s gr gr % arrowhead n 4320 3222 m 4350 3102 l 4380 3222 l 4350 3222 l 4320 3222 l cp gs 0.00 setgray ef gr col0 s % arrowhead n 4380 3828 m 4350 3948 l 4320 3828 l 4350 3828 l 4380 3828 l cp gs 0.00 setgray ef gr col0 s % Polyline [60] 0 sd n 4350 4350 m 4350 5475 l gs col0 s gr [] 0 sd % Polyline gs clippath 4021 5328 m 4039 5450 l 3966 5351 l 4028 5500 l 4083 5477 l cp clip n 2550 1875 m 4050 5475 l gs col0 s gr gr % arrowhead n 4021 5328 m 4039 5450 l 3966 5351 l 3993 5339 l 4021 5328 l cp gs 0.00 setgray ef gr col0 s % Polyline gs clippath 4380 2628 m 4350 2748 l 4320 2628 l 4320 2790 l 4380 2790 l cp 4320 2022 m 4350 1902 l 4380 2022 l 4380 1860 l 4320 1860 l cp clip n 4350 1875 m 4350 2775 l gs col0 s gr gr % arrowhead n 4320 2022 m 4350 1902 l 4380 2022 l 4350 2022 l 4320 2022 l cp gs 0.00 setgray ef gr col0 s % arrowhead n 4380 2628 m 4350 2748 l 4320 2628 l 4350 2628 l 4380 2628 l cp gs 0.00 setgray ef gr col0 s % Polyline gs clippath 3903 1695 m 4023 1725 l 3903 1755 l 4065 1755 l 4065 1695 l cp clip n 2550 1725 m 4050 1725 l gs col0 s gr gr % arrowhead n 3903 1695 m 4023 1725 l 3903 1755 l 3903 1725 l 3903 1695 l cp gs 0.00 setgray ef gr col0 s % Polyline gs clippath 6828 1695 m 6948 1725 l 6828 1755 l 6990 1755 l 6990 1695 l cp clip n 4725 1725 m 6975 1725 l gs col0 s gr gr % arrowhead n 6828 1695 m 6948 1725 l 6828 1755 l 6828 1725 l 6828 1695 l cp gs 0.00 setgray ef gr col0 s % Polyline [60] 0 sd n 7275 1950 m 7275 2625 l gs col0 s gr [] 0 sd /Times-Roman ff 180.00 scf sf 2100 1800 m gs 1 -1 sc (head) col0 sh gr /Times-Roman ff 180.00 scf sf 4200 1800 m gs 1 -1 sc (node) col0 sh gr /Times-Roman ff 180.00 scf sf 4200 3000 m gs 1 -1 sc (node) col0 sh gr /Times-Roman ff 180.00 scf sf 4200 4200 m gs 1 -1 sc (node) col0 sh gr /Times-Roman ff 180.00 scf sf 4200 5700 m gs 1 -1 sc (node) col0 sh gr /Times-Roman ff 180.00 scf sf 4575 2250 m gs 1 -1 sc (next sibling) col0 sh gr /Times-Roman ff 180.00 scf sf 4575 2475 m gs 1 -1 sc (prev sibling) col0 sh gr /Times-Roman ff 180.00 scf sf 4575 3450 m gs 1 -1 sc (next sibling) col0 sh gr /Times-Roman ff 180.00 scf sf 4575 3675 m gs 1 -1 sc (prev sibling) col0 sh gr /Times-Roman ff 180.00 scf sf 5850 1650 m gs 1 -1 sc (first child) col0 sh gr /Times-Roman ff 180.00 scf sf 2925 1650 m gs 1 -1 sc (first child) col0 sh gr /Times-Roman ff 180.00 scf sf 7125 1800 m gs 1 -1 sc (node) col0 sh gr /Times-Roman ff 180.00 scf sf 7125 2925 m gs 1 -1 sc (node) col0 sh gr /Times-Roman ff 180.00 scf sf 2550 3900 m gs 1 -1 sc (last child) col0 sh gr $F2psEnd rs cadabra-1.39/doc/treefig.fig000066400000000000000000000026051234107666300157170ustar00rootroot00000000000000#FIG 3.2 Landscape Center Inches Letter 100.00 Single -2 1200 2 2 1 0 1 0 7 0 0 -1 0.000 0 0 -1 1 1 2 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 4350 3075 4350 3975 2 1 1 1 0 7 0 0 -1 4.000 0 0 -1 0 0 2 4350 4350 4350 5475 2 1 0 1 0 7 0 0 -1 4.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 2550 1875 4050 5475 2 1 0 1 0 7 0 0 -1 0.000 0 0 -1 1 1 2 1 1 1.00 60.00 120.00 1 1 1.00 60.00 120.00 4350 1875 4350 2775 2 1 0 1 0 7 0 0 -1 0.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 2550 1725 4050 1725 2 1 0 1 0 7 0 0 -1 0.000 0 0 -1 1 0 2 1 1 1.00 60.00 120.00 4725 1725 6975 1725 2 1 1 1 0 7 0 0 -1 4.000 0 0 -1 0 0 2 7275 1950 7275 2625 4 0 0 0 0 0 12 0.0000 0 135 360 2100 1800 head\001 4 0 0 0 0 0 12 0.0000 4 135 360 4200 1800 node\001 4 0 0 0 0 0 12 0.0000 4 135 360 4200 3000 node\001 4 0 0 0 0 0 12 0.0000 4 135 360 4200 4200 node\001 4 0 0 0 0 0 12 0.0000 4 135 360 4200 5700 node\001 4 0 0 0 0 0 12 0.0000 4 180 870 4575 2250 next sibling\001 4 0 0 0 0 0 12 0.0000 4 180 870 4575 2475 prev sibling\001 4 0 0 0 0 0 12 0.0000 4 180 870 4575 3450 next sibling\001 4 0 0 0 0 0 12 0.0000 4 180 870 4575 3675 prev sibling\001 4 0 0 0 0 0 12 0.0000 4 135 720 5850 1650 first child\001 4 0 0 0 0 0 12 0.0000 4 135 720 2925 1650 first child\001 4 0 0 0 0 0 12 0.0000 4 135 360 7125 1800 node\001 4 0 0 0 0 0 12 0.0000 4 135 360 7125 2925 node\001 4 0 0 0 0 0 12 0.0000 4 135 690 2550 3900 last child\001 cadabra-1.39/doc/treefig.pdf000066400000000000000000000030701234107666300157200ustar00rootroot00000000000000%PDF-1.3 %쏢 6 0 obj <> stream xUK0WY}]HMPZ _hzE\/{b<{"?{($94lAjAh n NbNtJt%ʙƍ>v$+vjF_ŃSDRxqqXI3_k`?si*6:*=46cl%!HMpz$s>0RԕCKPcu[*5! Ƥ&˺c4@Nե.eΪipQT]h.̲I1N NH '׃sip.K٤Y rUB(!c7(]bIccX?فy VuAt43褙p 7YA/՜>xԠGwj VUju궕tES#됥HSwHo^6~+iܵ{gkR@voo ݲ.X̮ՋzΈ&~1$ ?w?G g[CO/|C |M I95_٩-kN)w-^cendstream endobj 7 0 obj 588 endobj 10 0 obj <> endobj 11 0 obj <> endobj 5 0 obj <> /Contents 6 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 5 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 4 0 obj <> endobj 9 0 obj <> endobj 8 0 obj <> endobj 2 0 obj <>endobj xref 0 12 0000000000 65535 f 0000000971 00000 n 0000001222 00000 n 0000000912 00000 n 0000001019 00000 n 0000000752 00000 n 0000000015 00000 n 0000000673 00000 n 0000001161 00000 n 0000001088 00000 n 0000000692 00000 n 0000000722 00000 n trailer << /Size 12 /Root 1 0 R /Info 2 0 R >> startxref 1274 %%EOF cadabra-1.39/doc/windows.txt000066400000000000000000000075121234107666300160400ustar00rootroot00000000000000 The windows version of Cadabra is built using Cygwin, with GTK libraries built to use native Windows widgets instead of an X11 server. This means that I did not use the Cygwin-supplied GTK libraries, but instead compiled my own set from source. A detailed log of the steps required to build Cadabra under Cygwin is given below (note that this may take several hours to complete due to the large number of dependencies of the gtkmm library). - install cygwin 1.7.5 or higher plus the packages Libs/ libpcrecpp-devel libgmp-devel libgmp3 libgmpxx4 libiconv gettext-devel libpng12-devel libtiff-devel Devel/ autoconf2.5 gcc4-g++ pkg-config make libtool Editors/ emacs Utils/ time Web/ wget - launch cygwin mkdir build cd build # Install libsigc++ wget http://ftp.gnome.org/pub/GNOME/sources/libsigc++/2.2/libsigc++-2.2.6.tar.bz2 tar jxvf libsigc++-2.2.6.tar.bz2 cd libsigc++-2.2.6 ./configure make make install # add 'export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig' to ~/.bashrc # Install modglue wget http://cadabra.phi-sci.com/modglue-1.16.tar.gz tar zxvf modglue-1.16.tar.gz cd modglue-1.16 ./configure make make install # Cadabra without GUI wget http://cadabra.phi-sci.com/cadabra-1.25.tar.gz tar zxvf cadabra-1.25.tar.gz cd cadabra-1.25 ./configure --disable-gui --disable-runtime-dependency-check make # 'make test' will now work but hang on fieldtheory.cdb because lie # is missing. # GUI prerequisites: # glib wget http://ftp.gnome.org/pub/gnome/sources/glib/2.25/glib-2.25.3.tar.bz2 tar jxf glib-2.25.3.tar.bz2 cd glib-2.25.3 # On line 1414 of glib/gstrfuncs.c remove 'extern const' from the declaration. ./configure; make; make install # pixman wget http://cairographics.org/releases/pixman-0.18.0.tar.gz tar zxf pixman-0.18.0.tar.gz cd pixman-0.18.0 ./configure; make; make install # cairo (previously, versions above 1.8.0 were broken?) wget http://cairographics.org/releases/cairo-1.8.10.tar.gz tar zxf cairo-1.8.10.tar.gz cd cairo-1.8.10 ./configure --enable-xlib=no make; make install # pango with cairo backend # (previously, in configure, add [_]* to the --export-symbols-regex for pango, # and export LIBS=-no-undefined too.) wget http://ftp.gnome.org/pub/GNOME/sources/pango/1.28/pango-1.28.0.tar.bz2 tar jxf pango-1.28.0.tar.bz2 cd pango-1.28.0.tar.bz2 ./configure --without-x --with-included-modules=yes make; make install # atk wget http://ftp.gnome.org/pub/GNOME/sources/atk/1.30/atk-1.30.0.tar.bz2 # gtk wget http://ftp.gnome.org/pub/GNOME/sources/gtk+/2.20/gtk+-2.20.0.tar.bz2 tar jxf gtk+-2.20.0.tar.bz2 cd gtk+-2.20.0 ./configure --without-x # on line 243 of gdk/win32/rc/Makefile, set WINDRES = windres. # on line 698, remove the -export-symbols $(srcdir)/gdk.def argument (already # covered by the -export-symbols-regex argument). make; make install # glibmm wget http://ftp.gnome.org/pub/GNOME/sources/glibmm/2.22/glibmm-2.22.2.tar.bz2 # cairomm wget http://cairographics.org/releases/cairomm-1.8.4.tar.gz # pangomm wget http://ftp.gnome.org/pub/GNOME/sources/pangomm/2.26/pangomm-2.26.1.tar.bz2 # gtkmm wget http://ftp.gnome.org/pub/GNOME/sources/gtkmm/2.18/gtkmm-2.18.2.tar.bz2 - install base miktex - set root - - install latest gtk (--without-x) - had to fix an issue with the deprecated gtk_scale_button_set_orientation, re-enable in .h file. - install a /usr/local/etc/pango/pango.aliases file - install latest glibmm - install cairomm 1.6.4 (1.8.0 fails to build) - install pangomm 2.24.0 - install gtkmm 2.14.3 drag crash: inner_window_procedure (hwnd=0xa6024a, message=71, wparam=0, lparam=2273744) at gdkevents-win32.c:3268 3268 if(_sizemove_in_progress && cadabra-1.39/doc/xperm.nb000066400000000000000000000777611234107666300152760ustar00rootroot00000000000000(* Content-type: application/mathematica *) (*** Wolfram Notebook File ***) (* http://www.wolfram.com/nb *) (* CreatedBy='Mathematica 7.0' *) (*CacheID: 234*) (* Internal cache information: NotebookFileLineBreakTest NotebookFileLineBreakTest NotebookDataPosition[ 145, 7] NotebookDataLength[ 32567, 931] NotebookOptionsPosition[ 29295, 828] NotebookOutlinePosition[ 29633, 843] CellTagsIndexPosition[ 29590, 840] WindowFrame->Normal*) (* Beginning of Notebook Content *) Notebook[{ Cell["\<\ This notebook is to verify that we are feeding the xperm routines correctly; \ we use the xTensor interface with Verbose->True to get a view on the required \ input to canonical_perm_ext.\ \>", "Text", CellChangeTimes->{{3.477558440265489*^9, 3.477558485407468*^9}}], Cell[CellGroupData[{ Cell[BoxData[ RowBox[{"<<", "xAct`xTensor`"}]], "Input", CellChangeTimes->{{3.477553000148336*^9, 3.477553004186784*^9}}], Cell[BoxData[ RowBox[{ RowBox[{"General", "::", "\<\"cdir\"\>"}], RowBox[{ ":", " "}], "\<\"\\!\\(\\*StyleBox[\\\"\\\\\\\"Cannot set current directory \ to \\\\\\\"\\\", \ \\\"MT\\\"]\\)\[NoBreak]\\!\\(\\*StyleBox[\\!\\(\\\"Paclets\\\"\\), \ \\\"MT\\\"]\\)\[NoBreak]\\!\\(\\*StyleBox[\\\"\\\\\\\".\\\\\\\"\\\", \\\"MT\\\ \"]\\)\"\>"}]], "Message", "MSG", CellChangeTimes->{3.477558300309192*^9}], Cell[BoxData[ RowBox[{ RowBox[{"Get", "::", "\<\"noopen\"\>"}], RowBox[{ ":", " "}], "\<\"\\!\\(\\*StyleBox[\\\"\\\\\\\"Cannot open \\\\\\\"\\\", \\\ \"MT\\\"]\\)\[NoBreak]\\!\\(\\*StyleBox[\\!\\(\\\"JLink`\\\"\\), \ \\\"MT\\\"]\\)\[NoBreak]\\!\\(\\*StyleBox[\\\"\\\\\\\".\\\\\\\"\\\", \\\"MT\\\ \"]\\)\"\>"}]], "Message", "MSG", CellChangeTimes->{3.477558306467509*^9}], Cell[BoxData[ RowBox[{ RowBox[{"Needs", "::", "\<\"nocont\"\>"}], RowBox[{ ":", " "}], "\<\"\\!\\(\\*StyleBox[\\\"\\\\\\\"Context \\\\\\\"\\\", \\\"MT\ \\\"]\\)\[NoBreak]\\!\\(\\*StyleBox[\\!\\(\\\"JLink`\\\"\\), \\\"MT\\\"]\\)\ \[NoBreak]\\!\\(\\*StyleBox[\\\"\\\\\\\" was not created when Needs was \ evaluated.\\\\\\\"\\\", \\\"MT\\\"]\\)\"\>"}]], "Message", "MSG", CellChangeTimes->{3.477558306474064*^9}], Cell[BoxData[ RowBox[{ RowBox[{"Get", "::", "\<\"noopen\"\>"}], RowBox[{ ":", " "}], "\<\"\\!\\(\\*StyleBox[\\\"\\\\\\\"Cannot open \\\\\\\"\\\", \\\ \"MT\\\"]\\)\[NoBreak]\\!\\(\\*StyleBox[\\!\\(\\\"JLink`\\\"\\), \ \\\"MT\\\"]\\)\[NoBreak]\\!\\(\\*StyleBox[\\\"\\\\\\\".\\\\\\\"\\\", \\\"MT\\\ \"]\\)\"\>"}]], "Message", "MSG", CellChangeTimes->{3.477558306762381*^9}], Cell[BoxData[ RowBox[{ RowBox[{"Needs", "::", "\<\"nocont\"\>"}], RowBox[{ ":", " "}], "\<\"\\!\\(\\*StyleBox[\\\"\\\\\\\"Context \\\\\\\"\\\", \\\"MT\ \\\"]\\)\[NoBreak]\\!\\(\\*StyleBox[\\!\\(\\\"JLink`\\\"\\), \\\"MT\\\"]\\)\ \[NoBreak]\\!\\(\\*StyleBox[\\\"\\\\\\\" was not created when Needs was \ evaluated.\\\\\\\"\\\", \\\"MT\\\"]\\)\"\>"}]], "Message", "MSG", CellChangeTimes->{3.477558306765708*^9}], Cell[BoxData[ RowBox[{ RowBox[{"$GeoLocation", "::", "\<\"dloff\"\>"}], RowBox[{ ":", " "}], "\<\"\\!\\(\\*StyleBox[\\\"\\\\\\\"Mathematica is currently \ configured not to use the internet, and could not download data for \ \\\\\\\"\\\", \ \\\"MT\\\"]\\)\[NoBreak]\\!\\(\\*StyleBox[\\!\\(\\\"$GeoLocation\\\"\\), \ \\\"MT\\\"]\\)\[NoBreak]\\!\\(\\*StyleBox[\\\"\\\\\\\". To allow internet \ access, use Help > Internet Connectivity...\\\\\\\"\\\", \ \\\"MT\\\"]\\)\"\>"}]], "Message", "MSG", CellChangeTimes->{3.477558308452268*^9}], Cell[CellGroupData[{ Cell[BoxData["\<\"------------------------------------------------------------\ \"\>"], "Print", CellChangeTimes->{3.477558308732259*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"Package xAct`xPerm` version \"\>", "\[InvisibleSpace]", "\<\"1.0.3\"\>", "\[InvisibleSpace]", "\<\", \"\>", "\[InvisibleSpace]", RowBox[{"{", RowBox[{"2009", ",", "9", ",", "9"}], "}"}]}], SequenceForm["Package xAct`xPerm` version ", "1.0.3", ", ", {2009, 9, 9}], Editable->False]], "Print", CellChangeTimes->{3.477558308949677*^9}], Cell[BoxData["\<\"CopyRight (C) 2003-2010, Jose M. Martin-Garcia, under the \ General Public License.\"\>"], "Print", CellChangeTimes->{3.477558308955469*^9}], Cell[BoxData["\<\"Connecting to external linux executable...\"\>"], "Print", CellChangeTimes->{3.477558308960744*^9}], Cell[BoxData["\<\"Connection established.\"\>"], "Print", CellChangeTimes->{3.47755830896575*^9}], Cell[BoxData["\<\"------------------------------------------------------------\ \"\>"], "Print", CellChangeTimes->{3.477558308971072*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"Package xAct`xTensor` version \"\>", "\[InvisibleSpace]", "\<\"0.9.9\"\>", "\[InvisibleSpace]", "\<\", \"\>", "\[InvisibleSpace]", RowBox[{"{", RowBox[{"2010", ",", "1", ",", "10"}], "}"}]}], SequenceForm[ "Package xAct`xTensor` version ", "0.9.9", ", ", {2010, 1, 10}], Editable->False]], "Print", CellChangeTimes->{3.477558308976452*^9}], Cell[BoxData["\<\"CopyRight (C) 2002-2010, Jose M. Martin-Garcia, under the \ General Public License.\"\>"], "Print", CellChangeTimes->{3.477558308982088*^9}], Cell[BoxData["\<\"------------------------------------------------------------\ \"\>"], "Print", CellChangeTimes->{3.477558308987423*^9}], Cell[BoxData["\<\"These packages come with ABSOLUTELY NO WARRANTY; for \ details type Disclaimer[]. This is free software, and you are welcome to \ redistribute it under certain conditions. See the General Public License for \ details.\"\>"], "Print", CellChangeTimes->{3.477558308993634*^9}], Cell[BoxData["\<\"------------------------------------------------------------\ \"\>"], "Print", CellChangeTimes->{3.477558309228697*^9}] }, Open ]] }, Open ]], Cell[CellGroupData[{ Cell[BoxData[ RowBox[{"DefManifold", "[", RowBox[{"M3", ",", " ", "3", ",", " ", RowBox[{"{", RowBox[{ "a", ",", "b", ",", "c", ",", "d", ",", "e", ",", "f", ",", "g", ",", "h"}], "}"}]}], "]"}]], "Input"], Cell[CellGroupData[{ Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"** \"\>", "\[InvisibleSpace]", "DefManifold", "\[InvisibleSpace]", "\<\": Defining \"\>", "\[InvisibleSpace]", "\<\"manifold \"\>", "\[InvisibleSpace]", "M3", "\[InvisibleSpace]", "\<\". \"\>", "\[InvisibleSpace]", "\<\"\"\>"}], SequenceForm[ "** ", xAct`xTensor`DefManifold, ": Defining ", "manifold ", $CellContext`M3, ". ", ""], Editable->False]], "Print", CellChangeTimes->{3.477558315248362*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"** \"\>", "\[InvisibleSpace]", "DefVBundle", "\[InvisibleSpace]", "\<\": Defining \"\>", "\[InvisibleSpace]", "\<\"vbundle \"\>", "\[InvisibleSpace]", "TangentM3", "\[InvisibleSpace]", "\<\". \"\>", "\[InvisibleSpace]", "\<\"\"\>"}], SequenceForm[ "** ", xAct`xTensor`DefVBundle, ": Defining ", "vbundle ", $CellContext`TangentM3, ". ", ""], Editable->False]], "Print", CellChangeTimes->{3.477558315452766*^9}] }, Open ]] }, Open ]], Cell[CellGroupData[{ Cell[BoxData[ RowBox[{"DefMetric", "[", RowBox[{ RowBox[{"-", "1"}], ",", RowBox[{"metricg", "[", RowBox[{ RowBox[{"-", "a"}], ",", RowBox[{"-", "b"}]}], "]"}], ",", "CD", ",", RowBox[{"PrintAs", "->", "\"\\""}]}], "]"}]], "Input"], Cell[CellGroupData[{ Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"** \"\>", "\[InvisibleSpace]", "DefTensor", "\[InvisibleSpace]", "\<\": Defining \"\>", "\[InvisibleSpace]", "\<\"symmetric metric tensor \"\>", "\[InvisibleSpace]", RowBox[{"metricg", "[", RowBox[{ RowBox[{"-", "a"}], ",", RowBox[{"-", "b"}]}], "]"}], "\[InvisibleSpace]", "\<\". \"\>", "\[InvisibleSpace]", "\<\"\"\>"}], SequenceForm[ "** ", xAct`xTensor`DefTensor, ": Defining ", "symmetric metric tensor ", $CellContext`metricg[-$CellContext`a, -$CellContext`b], ". ", ""], Editable->False]], "Print", CellChangeTimes->{3.477558317383238*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"** \"\>", "\[InvisibleSpace]", "DefTensor", "\[InvisibleSpace]", "\<\": Defining \"\>", "\[InvisibleSpace]", "\<\"antisymmetric tensor \"\>", "\[InvisibleSpace]", RowBox[{"epsilonmetricg", "[", RowBox[{"a", ",", "b", ",", "c"}], "]"}], "\[InvisibleSpace]", "\<\". \"\>", "\[InvisibleSpace]", "\<\"\"\>"}], SequenceForm[ "** ", xAct`xTensor`DefTensor, ": Defining ", "antisymmetric tensor ", $CellContext`epsilonmetricg[$CellContext`a, $CellContext`b, \ $CellContext`c], ". ", ""], Editable->False]], "Print", CellChangeTimes->{3.477558317518192*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"** \"\>", "\[InvisibleSpace]", "DefCovD", "\[InvisibleSpace]", "\<\": Defining \"\>", "\[InvisibleSpace]", "\<\"covariant derivative \"\>", "\[InvisibleSpace]", RowBox[{"CD", "[", RowBox[{"-", "a"}], "]"}], "\[InvisibleSpace]", "\<\". \"\>", "\[InvisibleSpace]", "\<\"\"\>"}], SequenceForm[ "** ", xAct`xTensor`DefCovD, ": Defining ", "covariant derivative ", $CellContext`CD[-$CellContext`a], ". ", ""], Editable->False]], "Print", CellChangeTimes->{3.477558317525181*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"** \"\>", "\[InvisibleSpace]", "DefTensor", "\[InvisibleSpace]", "\<\": Defining \"\>", "\[InvisibleSpace]", "\<\"vanishing torsion tensor \"\>", "\[InvisibleSpace]", RowBox[{"TorsionCD", "[", RowBox[{"a", ",", RowBox[{"-", "b"}], ",", RowBox[{"-", "c"}]}], "]"}], "\[InvisibleSpace]", "\<\". \"\>", "\[InvisibleSpace]", "\<\"\"\>"}], SequenceForm[ "** ", xAct`xTensor`DefTensor, ": Defining ", "vanishing torsion tensor ", $CellContext`TorsionCD[$CellContext`a, -$CellContext`b, -$CellContext`c], ". ", ""], Editable->False]], "Print", CellChangeTimes->{3.477558317530781*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"** \"\>", "\[InvisibleSpace]", "DefTensor", "\[InvisibleSpace]", "\<\": Defining \"\>", "\[InvisibleSpace]", "\<\"symmetric Christoffel tensor \"\>", "\[InvisibleSpace]", RowBox[{"ChristoffelCD", "[", RowBox[{"a", ",", RowBox[{"-", "b"}], ",", RowBox[{"-", "c"}]}], "]"}], "\[InvisibleSpace]", "\<\". \"\>", "\[InvisibleSpace]", "\<\"\"\>"}], SequenceForm[ "** ", xAct`xTensor`DefTensor, ": Defining ", "symmetric Christoffel tensor ", $CellContext`ChristoffelCD[$CellContext`a, -$CellContext`b, \ -$CellContext`c], ". ", ""], Editable->False]], "Print", CellChangeTimes->{3.477558317536536*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"** \"\>", "\[InvisibleSpace]", "DefTensor", "\[InvisibleSpace]", "\<\": Defining \"\>", "\[InvisibleSpace]", "\<\"Riemann tensor \"\>", "\[InvisibleSpace]", RowBox[{"RiemannCD", "[", RowBox[{ RowBox[{"-", "a"}], ",", RowBox[{"-", "b"}], ",", RowBox[{"-", "c"}], ",", RowBox[{"-", "d"}]}], "]"}], "\[InvisibleSpace]", "\<\". \"\>", "\[InvisibleSpace]", "\<\"\"\>"}], SequenceForm[ "** ", xAct`xTensor`DefTensor, ": Defining ", "Riemann tensor ", $CellContext`RiemannCD[-$CellContext`a, -$CellContext`b, -$CellContext`c, \ -$CellContext`d], ". ", ""], Editable->False]], "Print", CellChangeTimes->{3.477558317542215*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"** \"\>", "\[InvisibleSpace]", "DefTensor", "\[InvisibleSpace]", "\<\": Defining \"\>", "\[InvisibleSpace]", "\<\"symmetric Ricci tensor \"\>", "\[InvisibleSpace]", RowBox[{"RicciCD", "[", RowBox[{ RowBox[{"-", "a"}], ",", RowBox[{"-", "b"}]}], "]"}], "\[InvisibleSpace]", "\<\". \"\>", "\[InvisibleSpace]", "\<\"\"\>"}], SequenceForm[ "** ", xAct`xTensor`DefTensor, ": Defining ", "symmetric Ricci tensor ", $CellContext`RicciCD[-$CellContext`a, -$CellContext`b], ". ", ""], Editable->False]], "Print", CellChangeTimes->{3.477558317547962*^9}], Cell[BoxData["\<\"** DefCovD: Contractions of Riemann automatically replaced \ by Ricci.\"\>"], "Print", CellChangeTimes->{3.477558317745049*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"** \"\>", "\[InvisibleSpace]", "DefTensor", "\[InvisibleSpace]", "\<\": Defining \"\>", "\[InvisibleSpace]", "\<\"Ricci scalar \"\>", "\[InvisibleSpace]", RowBox[{"RicciScalarCD", "[", "]"}], "\[InvisibleSpace]", "\<\". \"\>", "\[InvisibleSpace]", "\<\"\"\>"}], SequenceForm[ "** ", xAct`xTensor`DefTensor, ": Defining ", "Ricci scalar ", $CellContext`RicciScalarCD[], ". ", ""], Editable->False]], "Print", CellChangeTimes->{3.477558318130119*^9}], Cell[BoxData["\<\"** DefCovD: Contractions of Ricci automatically replaced \ by RicciScalar.\"\>"], "Print", CellChangeTimes->{3.477558318308976*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"** \"\>", "\[InvisibleSpace]", "DefTensor", "\[InvisibleSpace]", "\<\": Defining \"\>", "\[InvisibleSpace]", "\<\"symmetric Einstein tensor \"\>", "\[InvisibleSpace]", RowBox[{"EinsteinCD", "[", RowBox[{ RowBox[{"-", "a"}], ",", RowBox[{"-", "b"}]}], "]"}], "\[InvisibleSpace]", "\<\". \"\>", "\[InvisibleSpace]", "\<\"\"\>"}], SequenceForm[ "** ", xAct`xTensor`DefTensor, ": Defining ", "symmetric Einstein tensor ", $CellContext`EinsteinCD[-$CellContext`a, -$CellContext`b], ". ", ""], Editable->False]], "Print", CellChangeTimes->{3.477558318506463*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"** \"\>", "\[InvisibleSpace]", "DefTensor", "\[InvisibleSpace]", "\<\": Defining \"\>", "\[InvisibleSpace]", "\<\"vanishing Weyl tensor \"\>", "\[InvisibleSpace]", RowBox[{"WeylCD", "[", RowBox[{ RowBox[{"-", "a"}], ",", RowBox[{"-", "b"}], ",", RowBox[{"-", "c"}], ",", RowBox[{"-", "d"}]}], "]"}], "\[InvisibleSpace]", "\<\". \"\>", "\[InvisibleSpace]", "\<\"\"\>"}], SequenceForm[ "** ", xAct`xTensor`DefTensor, ": Defining ", "vanishing Weyl tensor ", $CellContext`WeylCD[-$CellContext`a, -$CellContext`b, -$CellContext`c, \ -$CellContext`d], ". ", ""], Editable->False]], "Print", CellChangeTimes->{3.477558318852673*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"** \"\>", "\[InvisibleSpace]", "DefTensor", "\[InvisibleSpace]", "\<\": Defining \"\>", "\[InvisibleSpace]", "\<\"symmetric TFRicci tensor \"\>", "\[InvisibleSpace]", RowBox[{"TFRicciCD", "[", RowBox[{ RowBox[{"-", "a"}], ",", RowBox[{"-", "b"}]}], "]"}], "\[InvisibleSpace]", "\<\". \"\>", "\[InvisibleSpace]", "\<\"\"\>"}], SequenceForm[ "** ", xAct`xTensor`DefTensor, ": Defining ", "symmetric TFRicci tensor ", $CellContext`TFRicciCD[-$CellContext`a, -$CellContext`b], ". ", ""], Editable->False]], "Print", CellChangeTimes->{3.477558319212433*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"** \"\>", "\[InvisibleSpace]", "DefTensor", "\[InvisibleSpace]", "\<\": Defining \"\>", "\[InvisibleSpace]", "\<\"Kretschmann scalar \"\>", "\[InvisibleSpace]", RowBox[{"KretschmannCD", "[", "]"}], "\[InvisibleSpace]", "\<\". \"\>", "\[InvisibleSpace]", "\<\"\"\>"}], SequenceForm[ "** ", xAct`xTensor`DefTensor, ": Defining ", "Kretschmann scalar ", $CellContext`KretschmannCD[], ". ", ""], Editable->False]], "Print", CellChangeTimes->{3.477558319632501*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"** DefCovD: Computing RiemannToWeylRules for dim \"\>", "\[InvisibleSpace]", "3"}], SequenceForm["** DefCovD: Computing RiemannToWeylRules for dim ", 3], Editable->False]], "Print", CellChangeTimes->{3.477558320047561*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"** DefCovD: Computing RicciToTFRicci for dim \"\>", "\[InvisibleSpace]", "3"}], SequenceForm["** DefCovD: Computing RicciToTFRicci for dim ", 3], Editable->False]], "Print", CellChangeTimes->{3.477558320409797*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"** DefCovD: Computing RicciToEinsteinRules for dim \"\>", "\[InvisibleSpace]", "3"}], SequenceForm["** DefCovD: Computing RicciToEinsteinRules for dim ", 3], Editable->False]], "Print", CellChangeTimes->{3.477558320785704*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"** \"\>", "\[InvisibleSpace]", "DefTensor", "\[InvisibleSpace]", "\<\": Defining \"\>", "\[InvisibleSpace]", "\<\"weight +2 density \"\>", "\[InvisibleSpace]", RowBox[{"Detmetricg", "[", "]"}], "\[InvisibleSpace]", "\<\". \"\>", "\[InvisibleSpace]", "\<\"Determinant.\"\>"}], SequenceForm[ "** ", xAct`xTensor`DefTensor, ": Defining ", "weight +2 density ", $CellContext`Detmetricg[], ". ", "Determinant."], Editable->False]], "Print", CellChangeTimes->{3.477558321242839*^9}] }, Open ]] }, Open ]], Cell[CellGroupData[{ Cell[BoxData[ RowBox[{"DefTensor", "[", RowBox[{ RowBox[{"K", "[", RowBox[{ RowBox[{"-", "a"}], ",", "b"}], "]"}], ",", RowBox[{"{", "M3", "}"}]}], "]"}]], "Input", CellChangeTimes->{{3.477553093632021*^9, 3.477553104741367*^9}}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"** \"\>", "\[InvisibleSpace]", "DefTensor", "\[InvisibleSpace]", "\<\": Defining \"\>", "\[InvisibleSpace]", "\<\"tensor \"\>", "\[InvisibleSpace]", RowBox[{"K", "[", RowBox[{ RowBox[{"-", "a"}], ",", "b"}], "]"}], "\[InvisibleSpace]", "\<\". \"\>", "\[InvisibleSpace]", "\<\"\"\>"}], SequenceForm["** ", xAct`xTensor`DefTensor, ": Defining ", "tensor ", K[-$CellContext`a, $CellContext`b], ". ", ""], Editable->False]], "Print", CellChangeTimes->{3.477553105059203*^9, 3.477558326387298*^9}] }, Open ]], Cell[CellGroupData[{ Cell[BoxData[ RowBox[{"ToCanonical", "[", RowBox[{ RowBox[{"K", "[", RowBox[{ RowBox[{"-", "a"}], ",", "a"}], "]"}], ",", RowBox[{"Verbose", "\[Rule]", "True"}]}], "]"}]], "Input", CellChangeTimes->{{3.477553107972811*^9, 3.477553133814329*^9}}], Cell[CellGroupData[{ Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"ToCanonicalOne:: Actual configuration: \"\>", "\[InvisibleSpace]", RowBox[{"{", RowBox[{ RowBox[{"-", "a"}], ",", "a"}], "}"}]}], SequenceForm["ToCanonicalOne:: Actual configuration: ", xAct`xTensor`IndexList[-$CellContext`a, $CellContext`a]], Editable->False]], "Print", CellChangeTimes->{3.477553134114295*^9, 3.477558328169052*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"ToCanonicalOne:: Standard configuration: \"\>", "\[InvisibleSpace]", RowBox[{"{", RowBox[{"a", ",", RowBox[{"-", "a"}]}], "}"}]}], SequenceForm["ToCanonicalOne:: Standard configuration: ", xAct`xTensor`IndexList[$CellContext`a, -$CellContext`a]], Editable->False]], "Print", CellChangeTimes->{3.477553134114295*^9, 3.477558328181335*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"ToCanonicalOne:: Repeated indices: \"\>", "\[InvisibleSpace]", RowBox[{"{", "}"}]}], SequenceForm["ToCanonicalOne:: Repeated indices: ", xAct`xTensor`IndexList[]], Editable->False]], "Print", CellChangeTimes->{3.477553134114295*^9, 3.477558328187094*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"ToCanonicalOne:: Repeated indices: \"\>", "\[InvisibleSpace]", RowBox[{"{", "}"}]}], SequenceForm["ToCanonicalOne:: Repeated indices: ", {}], Editable->False]], "Print", CellChangeTimes->{3.477553134114295*^9, 3.477558328192679*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"ToCanonicalOne:: Permutation to be canonicalized: \"\>", "\[InvisibleSpace]", RowBox[{"Images", "[", RowBox[{"{", RowBox[{"2", ",", "1"}], "}"}], "]"}]}], SequenceForm["ToCanonicalOne:: Permutation to be canonicalized: ", xAct`xPerm`Images[{2, 1}]], Editable->False]], "Print", CellChangeTimes->{3.477553134114295*^9, 3.477558328198019*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"dummies: \"\>", "\[InvisibleSpace]", RowBox[{"{", "a", "}"}]}], SequenceForm["dummies: ", xAct`xTensor`IndexList[$CellContext`a]], Editable->False]], "Print", CellChangeTimes->{3.477553134114295*^9, 3.477558328203057*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"ToCanonicalOne:: dummysets_tmp: \"\>", "\[InvisibleSpace]", RowBox[{"{", RowBox[{"DummySet", "[", RowBox[{"TangentM3", ",", RowBox[{"{", "a", "}"}], ",", "1"}], "]"}], "}"}]}], SequenceForm["ToCanonicalOne:: dummysets_tmp: ", { xAct`xPerm`DummySet[$CellContext`TangentM3, {$CellContext`a}, 1]}], Editable->False]], "Print", CellChangeTimes->{3.477553134114295*^9, 3.477558328447033*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"ToCanonicalOne:: dummysets: \"\>", "\[InvisibleSpace]", RowBox[{"{", RowBox[{"DummySet", "[", RowBox[{"TangentM3", ",", RowBox[{"{", RowBox[{"{", RowBox[{"1", ",", "2"}], "}"}], "}"}], ",", "1"}], "]"}], "}"}]}], SequenceForm["ToCanonicalOne:: dummysets: ", { xAct`xPerm`DummySet[$CellContext`TangentM3, {{1, 2}}, 1]}], Editable->False]], "Print", CellChangeTimes->{3.477553134114295*^9, 3.477558328927886*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"ToCanonicalOne:: Free indices: \"\>", "\[InvisibleSpace]", RowBox[{"{", "}"}]}], SequenceForm["ToCanonicalOne:: Free indices: ", {}], Editable->False]], "Print", CellChangeTimes->{3.477553134114295*^9, 3.47755832939668*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"ToCanonicalOne:: calling: \"\>", "\[InvisibleSpace]", "\<\"CanonicalPerm[\"\>", "\[InvisibleSpace]", RowBox[{"Images", "[", RowBox[{"{", RowBox[{"2", ",", "1"}], "}"}], "]"}], "\[InvisibleSpace]", "\<\",\"\>", "\[InvisibleSpace]", "2", "\[InvisibleSpace]", "\<\",\"\>", "\[InvisibleSpace]", RowBox[{"StrongGenSet", "[", RowBox[{ RowBox[{"{", "}"}], ",", RowBox[{"GenSet", "[", "]"}]}], "]"}], "\[InvisibleSpace]", "\<\",\"\>", "\[InvisibleSpace]", RowBox[{"{", "}"}], "\[InvisibleSpace]", "\<\",\"\>", "\[InvisibleSpace]", RowBox[{"{", RowBox[{"DummySet", "[", RowBox[{"TangentM3", ",", RowBox[{"{", RowBox[{"{", RowBox[{"1", ",", "2"}], "}"}], "}"}], ",", "1"}], "]"}], "}"}], "\[InvisibleSpace]", "\<\",\"\>", "\[InvisibleSpace]", RowBox[{"Verbose", "\[Rule]", "True"}], "\[InvisibleSpace]", "\<\"]\"\>"}], SequenceForm["ToCanonicalOne:: calling: ", "CanonicalPerm[", xAct`xPerm`Images[{2, 1}], ",", 2, ",", xAct`xPerm`StrongGenSet[{}, xAct`xPerm`GenSet[]], ",", {}, ",", { xAct`xPerm`DummySet[$CellContext`TangentM3, {{1, 2}}, 1]}, ",", Verbose -> True, "]"], Editable->False]], "Print", CellChangeTimes->{3.477553134114295*^9, 3.477558329877726*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"ToCanonicalOne:: Canonical permutation: \"\>", "\[InvisibleSpace]", RowBox[{"Images", "[", RowBox[{"{", RowBox[{"1", ",", "2"}], "}"}], "]"}]}], SequenceForm["ToCanonicalOne:: Canonical permutation: ", xAct`xPerm`Images[{1, 2}]], Editable->False]], "Print", CellChangeTimes->{3.477553134114295*^9, 3.477558330350803*^9}] }, Open ]], Cell[BoxData[ InterpretationBox[ StyleBox[ SubsuperscriptBox["K", RowBox[{" ", "a"}], RowBox[{"a", " "}]], AutoSpacing->False], K[$CellContext`a, -$CellContext`a], Editable->False]], "Output", CellChangeTimes->{{3.477553120844582*^9, 3.477553134658614*^9}, 3.477558330937072*^9}] }, Open ]], Cell[CellGroupData[{ Cell[BoxData[ RowBox[{"ToCanonical", "[", RowBox[{ RowBox[{"K", "[", RowBox[{"a", ",", RowBox[{"-", "a"}]}], "]"}], ",", RowBox[{"Verbose", "\[Rule]", "True"}]}], "]"}]], "Input", CellChangeTimes->{{3.477553107972811*^9, 3.477553139652616*^9}}], Cell[CellGroupData[{ Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"ToCanonicalOne:: Actual configuration: \"\>", "\[InvisibleSpace]", RowBox[{"{", RowBox[{"a", ",", RowBox[{"-", "a"}]}], "}"}]}], SequenceForm["ToCanonicalOne:: Actual configuration: ", xAct`xTensor`IndexList[$CellContext`a, -$CellContext`a]], Editable->False]], "Print", CellChangeTimes->{3.477553139945665*^9, 3.477558333200656*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"ToCanonicalOne:: Standard configuration: \"\>", "\[InvisibleSpace]", RowBox[{"{", RowBox[{"a", ",", RowBox[{"-", "a"}]}], "}"}]}], SequenceForm["ToCanonicalOne:: Standard configuration: ", xAct`xTensor`IndexList[$CellContext`a, -$CellContext`a]], Editable->False]], "Print", CellChangeTimes->{3.477553139945665*^9, 3.477558333280906*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"ToCanonicalOne:: Repeated indices: \"\>", "\[InvisibleSpace]", RowBox[{"{", "}"}]}], SequenceForm["ToCanonicalOne:: Repeated indices: ", xAct`xTensor`IndexList[]], Editable->False]], "Print", CellChangeTimes->{3.477553139945665*^9, 3.477558333476301*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"ToCanonicalOne:: Repeated indices: \"\>", "\[InvisibleSpace]", RowBox[{"{", "}"}]}], SequenceForm["ToCanonicalOne:: Repeated indices: ", {}], Editable->False]], "Print", CellChangeTimes->{3.477553139945665*^9, 3.477558333689287*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"ToCanonicalOne:: Permutation to be canonicalized: \"\>", "\[InvisibleSpace]", RowBox[{"Images", "[", RowBox[{"{", RowBox[{"1", ",", "2"}], "}"}], "]"}]}], SequenceForm["ToCanonicalOne:: Permutation to be canonicalized: ", xAct`xPerm`Images[{1, 2}]], Editable->False]], "Print", CellChangeTimes->{3.477553139945665*^9, 3.477558333711472*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"dummies: \"\>", "\[InvisibleSpace]", RowBox[{"{", "a", "}"}]}], SequenceForm["dummies: ", xAct`xTensor`IndexList[$CellContext`a]], Editable->False]], "Print", CellChangeTimes->{3.477553139945665*^9, 3.477558333744224*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"ToCanonicalOne:: dummysets_tmp: \"\>", "\[InvisibleSpace]", RowBox[{"{", RowBox[{"DummySet", "[", RowBox[{"TangentM3", ",", RowBox[{"{", "a", "}"}], ",", "1"}], "]"}], "}"}]}], SequenceForm["ToCanonicalOne:: dummysets_tmp: ", { xAct`xPerm`DummySet[$CellContext`TangentM3, {$CellContext`a}, 1]}], Editable->False]], "Print", CellChangeTimes->{3.477553139945665*^9, 3.477558333773666*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"ToCanonicalOne:: dummysets: \"\>", "\[InvisibleSpace]", RowBox[{"{", RowBox[{"DummySet", "[", RowBox[{"TangentM3", ",", RowBox[{"{", RowBox[{"{", RowBox[{"1", ",", "2"}], "}"}], "}"}], ",", "1"}], "]"}], "}"}]}], SequenceForm["ToCanonicalOne:: dummysets: ", { xAct`xPerm`DummySet[$CellContext`TangentM3, {{1, 2}}, 1]}], Editable->False]], "Print", CellChangeTimes->{3.477553139945665*^9, 3.477558333807016*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"ToCanonicalOne:: Free indices: \"\>", "\[InvisibleSpace]", RowBox[{"{", "}"}]}], SequenceForm["ToCanonicalOne:: Free indices: ", {}], Editable->False]], "Print", CellChangeTimes->{3.477553139945665*^9, 3.477558333840153*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"ToCanonicalOne:: calling: \"\>", "\[InvisibleSpace]", "\<\"CanonicalPerm[\"\>", "\[InvisibleSpace]", RowBox[{"Images", "[", RowBox[{"{", RowBox[{"1", ",", "2"}], "}"}], "]"}], "\[InvisibleSpace]", "\<\",\"\>", "\[InvisibleSpace]", "2", "\[InvisibleSpace]", "\<\",\"\>", "\[InvisibleSpace]", RowBox[{"StrongGenSet", "[", RowBox[{ RowBox[{"{", "}"}], ",", RowBox[{"GenSet", "[", "]"}]}], "]"}], "\[InvisibleSpace]", "\<\",\"\>", "\[InvisibleSpace]", RowBox[{"{", "}"}], "\[InvisibleSpace]", "\<\",\"\>", "\[InvisibleSpace]", RowBox[{"{", RowBox[{"DummySet", "[", RowBox[{"TangentM3", ",", RowBox[{"{", RowBox[{"{", RowBox[{"1", ",", "2"}], "}"}], "}"}], ",", "1"}], "]"}], "}"}], "\[InvisibleSpace]", "\<\",\"\>", "\[InvisibleSpace]", RowBox[{"Verbose", "\[Rule]", "True"}], "\[InvisibleSpace]", "\<\"]\"\>"}], SequenceForm["ToCanonicalOne:: calling: ", "CanonicalPerm[", xAct`xPerm`Images[{1, 2}], ",", 2, ",", xAct`xPerm`StrongGenSet[{}, xAct`xPerm`GenSet[]], ",", {}, ",", { xAct`xPerm`DummySet[$CellContext`TangentM3, {{1, 2}}, 1]}, ",", Verbose -> True, "]"], Editable->False]], "Print", CellChangeTimes->{3.477553139945665*^9, 3.477558333876254*^9}], Cell[BoxData[ InterpretationBox[ RowBox[{"\<\"ToCanonicalOne:: Canonical permutation: \"\>", "\[InvisibleSpace]", RowBox[{"Images", "[", RowBox[{"{", RowBox[{"1", ",", "2"}], "}"}], "]"}]}], SequenceForm["ToCanonicalOne:: Canonical permutation: ", xAct`xPerm`Images[{1, 2}]], Editable->False]], "Print", CellChangeTimes->{3.477553139945665*^9, 3.477558333930378*^9}] }, Open ]], Cell[BoxData[ InterpretationBox[ StyleBox[ SubsuperscriptBox["K", RowBox[{" ", "a"}], RowBox[{"a", " "}]], AutoSpacing->False], K[$CellContext`a, -$CellContext`a], Editable->False]], "Output", CellChangeTimes->{{3.47755312861273*^9, 3.477553141079528*^9}, 3.47755833398521*^9}] }, Open ]] }, WindowSize->{908, 750}, WindowMargins->{{156, Automatic}, {10, Automatic}}, FrontEndVersion->"7.0 for Linux x86 (32-bit) (November 10, 2008)", StyleDefinitions->"Default.nb" ] (* End of Notebook Content *) (* Internal cache information *) (*CellTagsOutline CellTagsIndex->{} *) (*CellTagsIndex CellTagsIndex->{} *) (*NotebookFileOutline Notebook[{ Cell[545, 20, 277, 5, 51, "Text"], Cell[CellGroupData[{ Cell[847, 29, 123, 2, 32, "Input"], Cell[973, 33, 404, 9, 24, "Message"], Cell[1380, 44, 379, 8, 24, "Message"], Cell[1762, 54, 418, 8, 24, "Message"], Cell[2183, 64, 379, 8, 24, "Message"], Cell[2565, 74, 418, 8, 24, "Message"], Cell[2986, 84, 542, 11, 65, "Message"], Cell[CellGroupData[{ Cell[3553, 99, 138, 2, 24, "Print"], Cell[3694, 103, 405, 9, 24, "Print"], Cell[4102, 114, 159, 2, 24, "Print"], Cell[4264, 118, 118, 1, 24, "Print"], Cell[4385, 121, 98, 1, 24, "Print"], Cell[4486, 124, 138, 2, 24, "Print"], Cell[4627, 128, 414, 10, 24, "Print"], Cell[5044, 140, 159, 2, 24, "Print"], Cell[5206, 144, 138, 2, 24, "Print"], Cell[5347, 148, 293, 4, 65, "Print"], Cell[5643, 154, 138, 2, 24, "Print"] }, Open ]] }, Open ]], Cell[CellGroupData[{ Cell[5830, 162, 228, 6, 32, "Input"], Cell[CellGroupData[{ Cell[6083, 172, 472, 10, 24, "Print"], Cell[6558, 184, 482, 10, 24, "Print"] }, Open ]] }, Open ]], Cell[CellGroupData[{ Cell[7089, 200, 266, 8, 32, "Input"], Cell[CellGroupData[{ Cell[7380, 212, 642, 15, 24, "Print"], Cell[8025, 229, 634, 14, 24, "Print"], Cell[8662, 245, 558, 13, 24, "Print"], Cell[9223, 260, 678, 16, 24, "Print"], Cell[9904, 278, 696, 17, 24, "Print"], Cell[10603, 297, 722, 17, 24, "Print"], Cell[11328, 316, 640, 15, 24, "Print"], Cell[11971, 333, 147, 2, 24, "Print"], Cell[12121, 337, 524, 11, 24, "Print"], Cell[12648, 350, 151, 2, 24, "Print"], Cell[12802, 354, 656, 16, 24, "Print"], Cell[13461, 372, 730, 17, 24, "Print"], Cell[14194, 391, 648, 15, 24, "Print"], Cell[14845, 408, 536, 11, 24, "Print"], Cell[15384, 421, 282, 6, 24, "Print"], Cell[15669, 429, 274, 6, 24, "Print"], Cell[15946, 437, 286, 6, 24, "Print"], Cell[16235, 445, 552, 11, 24, "Print"] }, Open ]] }, Open ]], Cell[CellGroupData[{ Cell[16836, 462, 251, 7, 32, "Input"], Cell[17090, 471, 576, 12, 24, "Print"] }, Open ]], Cell[CellGroupData[{ Cell[17703, 488, 267, 7, 32, "Input"], Cell[CellGroupData[{ Cell[17995, 499, 410, 10, 24, "Print"], Cell[18408, 511, 414, 10, 24, "Print"], Cell[18825, 523, 320, 8, 24, "Print"], Cell[19148, 533, 294, 7, 24, "Print"], Cell[19445, 542, 417, 10, 24, "Print"], Cell[19865, 554, 283, 7, 24, "Print"], Cell[20151, 563, 466, 10, 24, "Print"], Cell[20620, 575, 507, 12, 24, "Print"], Cell[21130, 589, 281, 6, 24, "Print"], Cell[21414, 597, 1337, 32, 45, "Print"], Cell[22754, 631, 397, 10, 24, "Print"] }, Open ]], Cell[23166, 644, 307, 10, 31, "Output"] }, Open ]], Cell[CellGroupData[{ Cell[23510, 659, 267, 7, 32, "Input"], Cell[CellGroupData[{ Cell[23802, 670, 410, 10, 24, "Print"], Cell[24215, 682, 414, 10, 24, "Print"], Cell[24632, 694, 320, 8, 24, "Print"], Cell[24955, 704, 294, 7, 24, "Print"], Cell[25252, 713, 417, 10, 24, "Print"], Cell[25672, 725, 283, 7, 24, "Print"], Cell[25958, 734, 466, 10, 24, "Print"], Cell[26427, 746, 507, 12, 24, "Print"], Cell[26937, 760, 282, 6, 24, "Print"], Cell[27222, 768, 1337, 32, 45, "Print"], Cell[28562, 802, 397, 10, 24, "Print"] }, Open ]], Cell[28974, 815, 305, 10, 31, "Output"] }, Open ]] } ] *) (* End of internal cache information *) cadabra-1.39/doc/youngtab++.tex000066400000000000000000000111461234107666300163030ustar00rootroot00000000000000\documentclass{kasper} \usepackage{xspace} \usepackage{relsize} \renewcommand\descriptionlabel[1]{\hbox to \textwidth{\quad\quad\bf{#1}\hfill}} \newcommand{\ytt}{{\tt youngtab++}\xspace} \newcommand{\Ytt}{{\tt Youngtab++}\xspace} \begin{document} \title{\Ytt documentation} \maketitle \begin{abstract} The \ytt library is a small C++ library for the storage and manipulation of Young tableaux. Filled tableaux are supported with templates, allowing for any arbitrary object to be stored in the boxes that make up the tableaux. Several algorithms are included, among which an implementation of the Littlewood-Richardson algorithm for tensor products. Also included are pretty-print output functions acting on standard streams. \end{abstract} \begin{sectionunit} \title{Overview} \maketitle There are two tableau classes, one for tableaux without any information in the boxes and one for so-called filled tableaux. The latter are used just like STL containers. Two simple examples show the differences in initialisation. Unfilled tableaux only need to know about the row lengths and are therefore very quick to construct: \begin{screen} tableau tab; tab.add_row(3); tab.add_row(2); tab.add_row(2); \end{screen} Filled tableaux need to know about the content of each and every box: \begin{screen} filled_tableau ftab; ftab.add_box(0,''a''); ftab.add_box(0,''b''); ftab.add_box(0,''c''); ftab.add_box(1,''d''); ftab.add_box(1,''e''); ftab.add_box(2,''f''); ftab.add_box(2,''g''); \end{screen} There are many algorithms which do not act on a single tableau, but rather on a collection of them. There are special tableau containers to store such collections. For unfilled tableaux the canonical example is \begin{screen} tableaux tabs; tableau tab1, tab2; tabs.add_tableau(tab1); tabs.add_tableau(tab2); \end{screen} For filled tableaux, the container is templated over the tableau type (not over the data type stored in the boxes): \begin{screen} tableaux > ftabs; filled_tableau ftab1, ftab2; ftabs.add_tableau(ftab1); ftabs.add_tableau(ftab2); \end{screen} The tableaux added in this way are stored by value (just like in STL containers). \begin{sectionunit} \title{Tensor products} \maketitle The Littlewood-Richardson algorithm is implemented in two forms. The first one just takes two single tableaux and multiplies them, \begin{screen} tableau tab1,tab2; tableaux prod; LR_tensor(tab1, tab2, 10, prod.get_back_insert_iterator()); \end{screen} The ``10'' in the third argument indicates the maximum number of rows that is allowed. Observe that you give this algorithm an insert iterator to handle the storage of the tableaux in the product. In this way, it becomes independent of what you actually do with the tableaux in the product (you can store them, as in the example above, but you can also output them with an output iterator). In the second form, the Littlewood-Richardson algorithm takes a tableau container and a single tableau: \begin{screen} tableau tab1; tableaux tabs1, prod; LR_tensor(tabs1, tab1, 10, prod.get_back_insert_iterator()); \end{screen} The logic is the same, but now applied to a sum of representations as the first argument. \end{sectionunit} \begin{sectionunit} \title{Projectors} \maketitle \begin{screen} filled_tableau tab; tab.add_box(0, ``a''); tab.add_box(0, ``b''); tab.add_box(1, ``c''); symmetriser sym; tab.projector(sym); cout << sym << std::endl; \end{screen} This leads to \begin{screen} a b c 1 b a c 1 c b a -1 b c a -1 \end{screen} \end{sectionunit} \begin{sectionunit} \title{Canonicalisation and straightening} \maketitle Tableaux can be brought into canonical form by using anti-symmetry in sorting of the columns and symmetry under interchange of identical columns. For example, \begin{screen} filled_tableau tab; tab.add_box(0,4); tab.add_box(0,1); tab.add_box(1,3); tab.add_box(1,2); cout << tab << std::endl; tab.canonicalise(); cout << tab << std::endl; \end{screen} leads to the output \begin{screen} 4 1 3 2 1 3 (-1) 2 4 \end{screen} This was obtained by first sorting, using anti-symmetry, within the columns, and then sorting, using symmetry, the identical columns. Straightening of a tableau is canonicalisation plus a rewriting in terms of standard tableaux using Garnir symmetries. \end{sectionunit} \begin{description} \item[{\tt hook\_length(unsigned int row, unsigned int col)}] Compute the hook length of the hook with corner in the indicated box. \item[{\tt hook\_length\_prod}] Compute the product of all the hook lengths, giving the ``dimension'' of the tableau. \end{description} \end{sectionunit} \end{document} cadabra-1.39/examples/000077500000000000000000000000001234107666300146515ustar00rootroot00000000000000cadabra-1.39/examples/bianchi_identities.cnb000066400000000000000000000214331234107666300211560ustar00rootroot00000000000000% Cadabra notebook version 1.1 \documentclass[11pt]{article} \usepackage[textwidth=460pt, textheight=660pt]{geometry} \usepackage[usenames]{color} \usepackage{amssymb} \usepackage[parfill]{parskip} \usepackage{breqn} \usepackage{tableaux} \def\specialcolon{\mathrel{\mathop{:}}\hspace{-.5em}} \renewcommand{\bar}[1]{\overline{#1}} \begin{document} % Begin TeX cell closed {\large\bfseries Proof of the higher-derivative identity in appendix A of {\tt hep-th/0111128}} % End TeX cell % Begin TeX cell closed The declaration of the indices, Weyl tensor and covariant derivative: % End TeX cell {\color[named]{Blue}\begin{verbatim} {i,j,m,n,k,p,q,l,r,r#}::Indices(vector). C_{m n p q}::WeylTensor. \nabla{#}::Derivative. \nabla_{r}{ C_{m n p q} }::SatisfiesBianchi. \end{verbatim}} \begin{verbatim} Assigning list property Indices to i, j, m, n, k, p, q, l, r, r#. Assigning property WeylTensor to C. Assigning property Derivative to \nabla. Assigning property SatisfiesBianchi to \nabla. \end{verbatim} % Begin TeX cell closed The identity which we want to prove: % End TeX cell {\color[named]{Blue}\begin{verbatim} Eij:=- C_{i m k l} C_{j p k q} C_{l p m q} + 1/4 C_{i m k l} C_{j m p q} C_{k l p q} - 1/2 C_{i k j l} C_{k m p q} C_{l m p q}: E:= C_{j m n k} C_{m p q n} C_{p j k q} + 1/2 C_{j k m n} C_{p q m n} C_{j k p q}: exp:= \nabla_{i}{\nabla_{j}{ @(Eij) }} - 1/6 \nabla_{i}{\nabla_{i}{ @(E) }}; \end{verbatim}} % orig % \nabla_{i}{\nabla_{j}{( - C_{i m k l} C_{j p k q} C_{l p m q} + 1/4 C_{i m k l} C_{j m p q} C_{k l p q} - 1/2 C_{i k j l} C_{k m p q} C_{l m p q})}} - 1/6 \nabla_{i}{\nabla_{i}{(C_{j m n k} C_{m p q n} C_{p j k q} + 1/2 C_{j k m n} C_{p q m n} C_{j k p q})}}; % end_orig \begin{dmath*}[compact, spread=2pt] exp\specialcolon{}= \nabla_{i}{\nabla_{j}{( - C_{i m k l} C_{j p k q} C_{l p m q} + \frac{1}{4}\, C_{i m k l} C_{j m p q} C_{k l p q} - \frac{1}{2}\, C_{i k j l} C_{k m p q} C_{l m p q})}} - \frac{1}{6}\, \nabla_{i}{\nabla_{i}{(C_{j m n k} C_{m p q n} C_{p j k q} + \frac{1}{2}\, C_{j k m n} C_{p q m n} C_{j k p q})}}; \end{dmath*} % Begin TeX cell closed First apply the product rule to write out the derivatives, % End TeX cell {\color[named]{Blue}\begin{verbatim} @distribute!(%): @prodrule!(%): @distribute!(%): @prodrule!(%): @sumflatten!(%): @prodsort!(%): @canonicalise!(%): @rename_dummies!(%): @collect_terms!(%); \end{verbatim}} % orig % C_{i j m n} C_{i k m p} \nabla_{q}{\nabla_{j}{C_{n k p q}}} - C_{i j m n} \nabla_{k}{C_{i p m q}} \nabla_{p}{C_{j q n k}} - 2 C_{i j m n} \nabla_{i}{C_{m k p q}} \nabla_{p}{C_{j k n q}} - C_{i j m n} \nabla_{k}{C_{i k m p}} \nabla_{q}{C_{j p n q}} + C_{i j m n} C_{i k m p} \nabla_{j}{\nabla_{q}{C_{n k p q}}} - 2 C_{i j m n} \nabla_{i}{C_{j k m p}} \nabla_{q}{C_{n k p q}} - C_{i j m n} C_{i k p q} \nabla_{m}{\nabla_{p}{C_{j q n k}}} - 1/4 C_{i j m n} C_{i j k p} \nabla_{q}{\nabla_{m}{C_{n q k p}}} + 1/4 C_{i j m n} \nabla_{k}{C_{i j p q}} \nabla_{p}{C_{m n k q}} - 1/2 C_{i j m n} \nabla_{i}{C_{j k p q}} \nabla_{k}{C_{m n p q}} - 1/4 C_{i j m n} \nabla_{k}{C_{i j k p}} \nabla_{q}{C_{m n p q}} - 1/4 C_{i j m n} C_{i j k p} \nabla_{m}{\nabla_{q}{C_{n q k p}}} - 1/2 C_{i j m n} \nabla_{i}{C_{m n k p}} \nabla_{q}{C_{j q k p}} + 1/4 C_{i j m n} C_{i k p q} \nabla_{j}{\nabla_{k}{C_{m n p q}}} - 1/2 C_{i j m n} C_{i j m k} \nabla_{p}{\nabla_{q}{C_{n p k q}}} + C_{i j m n} \nabla_{k}{C_{i j m p}} \nabla_{q}{C_{n q k p}} - C_{i j m n} \nabla_{k}{C_{i j m p}} \nabla_{q}{C_{n k p q}} + 1/2 C_{i j m n} C_{i k p q} \nabla_{m}{\nabla_{j}{C_{n k p q}}} + 1/2 C_{i j m n} \nabla_{i}{C_{m k p q}} \nabla_{n}{C_{j k p q}} - 1/2 C_{i j m n} \nabla_{i}{C_{j k p q}} \nabla_{m}{C_{n k p q}} + 1/2 C_{i j m n} C_{i k p q} \nabla_{j}{\nabla_{m}{C_{n k p q}}} + 1/2 C_{i j m n} C_{i k m p} \nabla_{q}{\nabla_{q}{C_{j k n p}}} + C_{i j m n} \nabla_{k}{C_{i p m q}} \nabla_{k}{C_{j p n q}} - 1/4 C_{i j m n} C_{i j k p} \nabla_{q}{\nabla_{q}{C_{m n k p}}} - 1/2 C_{i j m n} \nabla_{k}{C_{i j p q}} \nabla_{k}{C_{m n p q}}; % end_orig \begin{dmath*}[compact, spread=2pt] exp\specialcolon{}= C_{i j m n} C_{i k m p} \nabla_{q}{\nabla_{j}{C_{n k p q}}} - C_{i j m n} \nabla_{k}{C_{i p m q}} \nabla_{p}{C_{j q n k}} - 2\, C_{i j m n} \nabla_{i}{C_{m k p q}} \nabla_{p}{C_{j k n q}} - C_{i j m n} \nabla_{k}{C_{i k m p}} \nabla_{q}{C_{j p n q}} + C_{i j m n} C_{i k m p} \nabla_{j}{\nabla_{q}{C_{n k p q}}} - 2\, C_{i j m n} \nabla_{i}{C_{j k m p}} \nabla_{q}{C_{n k p q}} - C_{i j m n} C_{i k p q} \nabla_{m}{\nabla_{p}{C_{j q n k}}} - \frac{1}{4}\, C_{i j m n} C_{i j k p} \nabla_{q}{\nabla_{m}{C_{n q k p}}} + \frac{1}{4}\, C_{i j m n} \nabla_{k}{C_{i j p q}} \nabla_{p}{C_{m n k q}} - \frac{1}{2}\, C_{i j m n} \nabla_{i}{C_{j k p q}} \nabla_{k}{C_{m n p q}} - \frac{1}{4}\, C_{i j m n} \nabla_{k}{C_{i j k p}} \nabla_{q}{C_{m n p q}} - \frac{1}{4}\, C_{i j m n} C_{i j k p} \nabla_{m}{\nabla_{q}{C_{n q k p}}} - \frac{1}{2}\, C_{i j m n} \nabla_{i}{C_{m n k p}} \nabla_{q}{C_{j q k p}} + \frac{1}{4}\, C_{i j m n} C_{i k p q} \nabla_{j}{\nabla_{k}{C_{m n p q}}} - \frac{1}{2}\, C_{i j m n} C_{i j m k} \nabla_{p}{\nabla_{q}{C_{n p k q}}} + C_{i j m n} \nabla_{k}{C_{i j m p}} \nabla_{q}{C_{n q k p}} - C_{i j m n} \nabla_{k}{C_{i j m p}} \nabla_{q}{C_{n k p q}} + \frac{1}{2}\, C_{i j m n} C_{i k p q} \nabla_{m}{\nabla_{j}{C_{n k p q}}} + \frac{1}{2}\, C_{i j m n} \nabla_{i}{C_{m k p q}} \nabla_{n}{C_{j k p q}}% - \frac{1}{2}\, C_{i j m n} \nabla_{i}{C_{j k p q}} \nabla_{m}{C_{n k p q}} + \frac{1}{2}\, C_{i j m n} C_{i k p q} \nabla_{j}{\nabla_{m}{C_{n k p q}}} + \frac{1}{2}\, C_{i j m n} C_{i k m p} \nabla_{q}{\nabla_{q}{C_{j k n p}}} + C_{i j m n} \nabla_{k}{C_{i p m q}} \nabla_{k}{C_{j p n q}} - \frac{1}{4}\, C_{i j m n} C_{i j k p} \nabla_{q}{\nabla_{q}{C_{m n k p}}} - \frac{1}{2}\, C_{i j m n} \nabla_{k}{C_{i j p q}} \nabla_{k}{C_{m n p q}}; \end{dmath*} % Begin TeX cell closed Because the identity which we intend to prove is only supposed to hold on Einstein spaces, we set the divergence of the Weyl tensor to zero, % End TeX cell {\color[named]{Blue}\begin{verbatim} @substitute!(%)( \nabla_{i}{C_{k i l m}} -> 0, \nabla_{i}{C_{k m l i}} -> 0 ); \end{verbatim}} % orig % C_{i j m n} C_{i k m p} \nabla_{q}{\nabla_{j}{C_{n k p q}}} - C_{i j m n} \nabla_{k}{C_{i p m q}} \nabla_{p}{C_{j q n k}} - 2 C_{i j m n} \nabla_{i}{C_{m k p q}} \nabla_{p}{C_{j k n q}} - C_{i j m n} C_{i k p q} \nabla_{m}{\nabla_{p}{C_{j q n k}}} - 1/4 C_{i j m n} C_{i j k p} \nabla_{q}{\nabla_{m}{C_{n q k p}}} + 1/4 C_{i j m n} \nabla_{k}{C_{i j p q}} \nabla_{p}{C_{m n k q}} - 1/2 C_{i j m n} \nabla_{i}{C_{j k p q}} \nabla_{k}{C_{m n p q}} + 1/4 C_{i j m n} C_{i k p q} \nabla_{j}{\nabla_{k}{C_{m n p q}}} + 1/2 C_{i j m n} C_{i k p q} \nabla_{m}{\nabla_{j}{C_{n k p q}}} + 1/2 C_{i j m n} \nabla_{i}{C_{m k p q}} \nabla_{n}{C_{j k p q}} - 1/2 C_{i j m n} \nabla_{i}{C_{j k p q}} \nabla_{m}{C_{n k p q}} + 1/2 C_{i j m n} C_{i k p q} \nabla_{j}{\nabla_{m}{C_{n k p q}}} + 1/2 C_{i j m n} C_{i k m p} \nabla_{q}{\nabla_{q}{C_{j k n p}}} + C_{i j m n} \nabla_{k}{C_{i p m q}} \nabla_{k}{C_{j p n q}} - 1/4 C_{i j m n} C_{i j k p} \nabla_{q}{\nabla_{q}{C_{m n k p}}} - 1/2 C_{i j m n} \nabla_{k}{C_{i j p q}} \nabla_{k}{C_{m n p q}}; % end_orig \begin{dmath*}[compact, spread=2pt] exp\specialcolon{}= C_{i j m n} C_{i k m p} \nabla_{q}{\nabla_{j}{C_{n k p q}}} - C_{i j m n} \nabla_{k}{C_{i p m q}} \nabla_{p}{C_{j q n k}} - 2\, C_{i j m n} \nabla_{i}{C_{m k p q}} \nabla_{p}{C_{j k n q}} - C_{i j m n} C_{i k p q} \nabla_{m}{\nabla_{p}{C_{j q n k}}} - \frac{1}{4}\, C_{i j m n} C_{i j k p} \nabla_{q}{\nabla_{m}{C_{n q k p}}} + \frac{1}{4}\, C_{i j m n} \nabla_{k}{C_{i j p q}} \nabla_{p}{C_{m n k q}} - \frac{1}{2}\, C_{i j m n} \nabla_{i}{C_{j k p q}} \nabla_{k}{C_{m n p q}} + \frac{1}{4}\, C_{i j m n} C_{i k p q} \nabla_{j}{\nabla_{k}{C_{m n p q}}} + \frac{1}{2}\, C_{i j m n} C_{i k p q} \nabla_{m}{\nabla_{j}{C_{n k p q}}} + \frac{1}{2}\, C_{i j m n} \nabla_{i}{C_{m k p q}} \nabla_{n}{C_{j k p q}} - \frac{1}{2}\, C_{i j m n} \nabla_{i}{C_{j k p q}} \nabla_{m}{C_{n k p q}} + \frac{1}{2}\, C_{i j m n} C_{i k p q} \nabla_{j}{\nabla_{m}{C_{n k p q}}} + \frac{1}{2}\, C_{i j m n} C_{i k m p} \nabla_{q}{\nabla_{q}{C_{j k n p}}} + C_{i j m n} \nabla_{k}{C_{i p m q}} \nabla_{k}{C_{j p n q}} - \frac{1}{4}\, C_{i j m n} C_{i j k p} \nabla_{q}{\nabla_{q}{C_{m n k p}}} - \frac{1}{2}\, C_{i j m n} \nabla_{k}{C_{i j p q}} \nabla_{k}{C_{m n p q}}; \end{dmath*} % Begin TeX cell closed This expression should vanish upon use of the Bianchi identity. By expanding all tensors using their Young projectors, this becomes manifest, % End TeX cell {\color[named]{Blue}\begin{verbatim} @young_project_tensor!3(%){ModuloMonoterm}: @distribute!(%): @prodsort!(%): @canonicalise!(%): @rename_dummies!(%): @collect_terms!(%); \end{verbatim}} % orig % 0; % end_orig \begin{dmath*}[compact, spread=2pt] exp\specialcolon{}= 0; \end{dmath*} % Begin TeX cell closed This proves the identity. % End TeX cell \end{document} cadabra-1.39/examples/fierz.cnb000066400000000000000000000074761234107666300164720ustar00rootroot00000000000000% Cadabra notebook version 1.0 \documentclass[11pt]{article} \usepackage[textwidth=460pt, textheight=660pt]{geometry} \usepackage[usenames]{color} \usepackage[parfill]{parskip} \usepackage{breqn} \def\specialcolon{\mathrel{\mathop{:}}\hspace{-.5em}} \renewcommand{\bar}[1]{\overline{#1}} \begin{document} % Begin TeX cell closed {\bfseries\large A Fierz identity in eleven dimensions} This notebook computes the Fierz identity (5.86) in my thesis. % End TeX cell {\color[named]{Blue}\begin{verbatim} {\mu,\nu,\rho}::Indices(curved, position=fixed). {m,n,p,q,r,s,t#}::Indices(flat). {m,n,p,q,r,s,t#}::Integer(0..10). T^{#{\mu}}::AntiSymmetric. \psi_{\mu}::SelfAntiCommuting. \psi_{\mu}::Spinor(dimension=11, type=Majorana). \theta::Spinor(dimension=11, type=Majorana). \epsilon::Spinor(dimension=11, type=Majorana). {\theta,\epsilon,\psi_{\mu}}::AntiCommuting \bar{#}::DiracBar. \delta^{m n}::KroneckerDelta. \Gamma^{#{m}}::GammaMatrix(metric=\delta). \end{verbatim}} \begin{verbatim} Assigning property Indices to \mu, \nu, \rho. Assigning property Indices to m, n, p, q, r, s, t#. Assigning property Integer to m, n, p, q, r, s, t#. Assigning property AntiSymmetric to T. Assigning property SelfAntiCommuting to \psi. Assigning property Spinor to \psi. Assigning property Spinor to \theta. Assigning property Spinor to \epsilon. Assigning property DiracBar to \bar. Assigning property AntiCommuting to \theta, \epsilon, \psi, {, \bar. Assigning property KroneckerDelta to \delta. Assigning property GammaMatrix to \Gamma. \end{verbatim} {\color[named]{Blue}\begin{verbatim} T^{\mu\nu\rho} e_{\nu}^{s} \bar{\theta} \Gamma^{r s} \psi_{\rho} \bar{\psi_{\mu}} \Gamma^{r} \epsilon; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 1\specialcolon{}= T^{\mu \nu \rho} e_{\nu}\,^{s} \bar{\theta} \Gamma^{r s} \psi_{\rho} \bar{\psi_{\mu}} \Gamma^{r} \epsilon; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @fierz!(%)( \theta, \epsilon, \psi_{\mu}, \psi_{\nu} ); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 1\specialcolon{}= - \frac{1}{32}\, T^{\mu \nu \rho} e_{\nu}\,^{s} \bar{\theta} \Gamma^{r s} \Gamma^{r} \epsilon \bar{\psi_{\mu}} \psi_{\rho} - \frac{1}{32}\, T^{\mu \nu \rho} e_{\nu}\,^{s} \bar{\theta} \Gamma^{r s} \Gamma_{m} \Gamma^{r} \epsilon \bar{\psi_{\mu}} \Gamma_{m} \psi_{\rho} - \frac{1}{64}\, T^{\mu \nu \rho} e_{\nu}\,^{s} \bar{\theta} \Gamma^{r s} \Gamma_{m n} \Gamma^{r} \epsilon \bar{\psi_{\mu}} \Gamma_{n m} \psi_{\rho} - \frac{1}{192}\, T^{\mu \nu \rho} e_{\nu}\,^{s} \bar{\theta} \Gamma^{r s} \Gamma_{m n p} \Gamma^{r} \epsilon \bar{\psi_{\mu}} \Gamma_{p n m} \psi_{\rho} - \frac{1}{768}\, T^{\mu \nu \rho} e_{\nu}\,^{s} \bar{\theta} \Gamma^{r s} \Gamma_{m n p q} \Gamma^{r} \epsilon \bar{\psi_{\mu}} \Gamma_{q p n m} \psi_{\rho} - \frac{1}{3840}\, T^{\mu \nu \rho} e_{\nu}\,^{s} \bar{\theta} \Gamma^{r s} \Gamma_{m n p q t1} \Gamma^{r} \epsilon \bar{\psi_{\mu}} \Gamma_{t1 q p n m} \psi_{\rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}: @distribute!(%): @eliminate_kr!(%): @join!(%){expand}: @distribute!(%): @eliminate_kr!(%): @collect_terms!(%): @canonicalise!(%): @rename_dummies!(%): @collect_terms!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 1\specialcolon{}= \frac{1}{4}\, T^{\mu \nu \rho} e_{\mu}\,^{m} \bar{\theta} \Gamma^{m n} \epsilon \bar{\psi_{\nu}} \Gamma_{n} \psi_{\rho} + \frac{5}{16}\, T^{\mu \nu \rho} e_{\mu}\,^{m} \bar{\theta} \epsilon \bar{\psi_{\nu}} \Gamma_{m} \psi_{\rho} + \frac{3}{32}\, T^{\mu \nu \rho} e_{\mu}\,^{m} \bar{\theta} \Gamma^{m n}\,_{p} \epsilon \bar{\psi_{\nu}} \Gamma_{n p} \psi_{\rho} + \frac{1}{4}\, T^{\mu \nu \rho} e_{\mu}\,^{m} \bar{\theta} \Gamma^{n} \epsilon \bar{\psi_{\nu}} \Gamma_{m n} \psi_{\rho} + \frac{1}{384}\, T^{\mu \nu \rho} e_{\mu}\,^{m} \bar{\theta} \Gamma^{n}\,_{p q r} \epsilon \bar{\psi_{\nu}} \Gamma_{m n p q r} \psi_{\rho}; \end{dmath*} \end{document} cadabra-1.39/examples/leo1.cnb000066400000000000000000000041101234107666300161710ustar00rootroot00000000000000% Cadabra notebook version 1.1 \documentclass[11pt]{article} \usepackage[textwidth=460pt, textheight=660pt]{geometry} \usepackage[dvipsnames,usenames]{color} \usepackage{amssymb} \usepackage[parfill]{parskip} \usepackage{breqn} \usepackage{tableaux} \def\specialcolon{\mathrel{\mathop{:}}\hspace{-.5em}} \renewcommand{\bar}[1]{\overline{#1}} \begin{document} {\color[named]{Blue}\begin{verbatim} {a,b,c,d}::Indices. \end{verbatim}} % Begin TeX comment Assigning list property Indices to $\{a,\; b,\; c,\; d\}$. \\ % End TeX comment {\color[named]{Blue}\begin{verbatim} R_{a b c d}::RiemannTensor. \end{verbatim}} % Begin TeX comment Assigning property RiemannTensor to ${R}_{a b c d}$. \\ % End TeX comment {\color[named]{Blue}\begin{verbatim} 2 R_{a b c d} R_{a c b d} - R_{a b c d} R_{a b c d}; \end{verbatim}} % orig % 2 R_{a b c d} R_{a c b d} - R_{a b c d} R_{a b c d} % end_orig \begin{dmath*}[compact, spread=2pt] 1\specialcolon{}= 2\, {R}_{a b c d} {R}_{a c b d} - {R}_{a b c d} {R}_{a b c d}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @young_project_product!(%); \end{verbatim}} % orig % (2/3 R_{a b c d} R_{a c b d} + 2/3 R_{a b c d} R_{a b c d}) + ( - 2/3 R_{a b c d} R_{a b c d} - 2/3 R_{a b c d} R_{a c b d}) % end_orig \begin{dmath*}[compact, spread=2pt] 1\specialcolon{}= (\frac{2}{3}\, {R}_{a b c d} {R}_{a c b d} + \frac{2}{3}\, {R}_{a b c d} {R}_{a b c d}) + ( - \frac{2}{3}\, {R}_{a b c d} {R}_{a b c d} - \frac{2}{3}\, {R}_{a b c d} {R}_{a c b d}); \end{dmath*} {\color[named]{Blue}\begin{verbatim} @sumflatten!(%); \end{verbatim}} % orig % 2/3 R_{a b c d} R_{a c b d} + 2/3 R_{a b c d} R_{a b c d} - 2/3 R_{a b c d} R_{a b c d} - 2/3 R_{a b c d} R_{a c b d} % end_orig \begin{dmath*}[compact, spread=2pt] 1\specialcolon{}= \frac{2}{3}\, {R}_{a b c d} {R}_{a c b d} + \frac{2}{3}\, {R}_{a b c d} {R}_{a b c d} - \frac{2}{3}\, {R}_{a b c d} {R}_{a b c d} - \frac{2}{3}\, {R}_{a b c d} {R}_{a c b d}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @collect_terms!(%); \end{verbatim}} % orig % 0 % end_orig \begin{dmath*}[compact, spread=2pt] 1\specialcolon{}= 0; \end{dmath*} \end{document} cadabra-1.39/examples/maxima.cnb000066400000000000000000000063151234107666300166160ustar00rootroot00000000000000% Cadabra notebook version 1.1 \documentclass[11pt]{article} \usepackage[textwidth=460pt, textheight=660pt]{geometry} \usepackage[usenames]{color} \usepackage{amssymb} \usepackage[parfill]{parskip} \usepackage{breqn} \usepackage{tableaux} \def\specialcolon{\mathrel{\mathop{:}}\hspace{-.5em}} \renewcommand{\bar}[1]{\overline{#1}} \begin{document} % Begin TeX cell closed \section*{\bf XCadabra as a Maxima front-end} The XCadabra notebook interface can be used as a front-end for the Maxima computer algebra system, by virtue of the \verb|@maxima| command. If you make this command part of the default rules, all input cells get evaluated by cadabra. % End TeX cell {\color[named]{Blue}\begin{verbatim} ::PostDefaultRules( @@maxima(%) ). \end{verbatim}} \begin{verbatim} Assigning property PostDefaultRules to . \end{verbatim} {\color[named]{Blue}\begin{verbatim} integrate( sin(x), x, 0, 3.14 ); \end{verbatim}} % orig % 1576947/788474; % end_orig \begin{dmath*}[compact, spread=2pt] 1\specialcolon{}= \frac{1576947}{788474}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} trigsimp( sin(x)**2 + cos(x)**2 ); \end{verbatim}} % orig % 1; % end_orig \begin{dmath*}[compact, spread=2pt] 2\specialcolon{}= 1; \end{dmath*} {\color[named]{Blue}\begin{verbatim} trigexpand( cos(a+b) ); \end{verbatim}} % orig % \cos(a) \cos(b) - \sin(a) \sin(b); % end_orig \begin{dmath*}[compact, spread=2pt] 3\specialcolon{}= \cos(a) \cos(b) - \sin(a) \sin(b); \end{dmath*} {\color[named]{Blue}\begin{verbatim} trigreduce( @(%) ); \end{verbatim}} % orig % \cos(b + a); % end_orig \begin{dmath*}[compact, spread=2pt] 4\specialcolon{}= \cos(b + a); \end{dmath*} {\color[named]{Blue}\begin{verbatim} powerseries(log(sin(x)/x), x, 0); \end{verbatim}} % orig % 1/2 'sum((-1)**i1 2**2 i1 bern(2 i1) x**2 i1/(i1 2 i1!), i1, 1, \infty); % end_orig \begin{dmath*}[compact, spread=2pt] 5\specialcolon{}= \frac{1}{2}\, 'sum((-1){}^{i1} 2{}^{2\, i1} bern(2\, i1) \frac{x{}^{2\, i1}}{(i1 2\, i1!)},\quad i1,\quad 1,\quad \infty); \end{dmath*} {\color[named]{Blue}\begin{verbatim} [1, 2, 7, x+y]; \end{verbatim}} % orig % [1, 2, 7, (y + x)]; % end_orig \begin{dmath*}[compact, spread=2pt] 6\specialcolon{}= [1,\quad 2,\quad 7,\quad (y + x)]; \end{dmath*} {\color[named]{Blue}\begin{verbatim} append( @(%), [4, sin(x)]); \end{verbatim}} % orig % [1, 2, 7, (y + x), 4, \sin(x)]; % end_orig \begin{dmath*}[compact, spread=2pt] 7\specialcolon{}= [1,\quad 2,\quad 7,\quad (y + x),\quad 4,\quad \sin(x)]; \end{dmath*} {\color[named]{Blue}\begin{verbatim} length( @(%) ); \end{verbatim}} % orig % 6; % end_orig \begin{dmath*}[compact, spread=2pt] 8\specialcolon{}= 6; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @length(7); \end{verbatim}} % orig % 6; % end_orig \begin{dmath*}[compact, spread=2pt] 7\specialcolon{}= 6; \end{dmath*} {\color[named]{Blue}\begin{verbatim} 'diff(f(x),x) = sin(x); \end{verbatim}} % orig % 'diff(f(x), x, 1) = \sin(x); % end_orig \begin{dmath*}[compact, spread=2pt] 9\specialcolon{}= 'diff(f(x),\quad x,\quad 1) = \sin(x); \end{dmath*} {\color[named]{Blue}\begin{verbatim} desolve( @(%), f(x) ); \end{verbatim}} % orig % f(x) = ( - \cos(x) + f(0) + 1); % end_orig \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= f(x) = ( - \cos(x) + f(0) + 1); \end{dmath*} \end{document} cadabra-1.39/examples/maxwell.cnb000066400000000000000000000105761234107666300170170ustar00rootroot00000000000000% Cadabra notebook version 1.0 \documentclass[11pt]{article} \usepackage[textwidth=460pt, textheight=660pt]{geometry} \usepackage[usenames]{color} \usepackage[parfill]{parskip} \usepackage{breqn} \def\specialcolon{\mathrel{\mathop{:}}\hspace{-.5em}} \renewcommand{\bar}[1]{\overline{#1}} \begin{document} {\color[named]{Blue}\begin{verbatim} { a,b,c,d,e }::Indices(vector). {\partial{#}, \nabla{#}}::PartialDerivative. { A_{a}, F_{a b} }::Depends(\partial). { a,b,c,d,e }::Indices(vector). \delta{#}::Accent. F_{a b}::AntiSymmetric. \delta_{a b}::KroneckerDelta. \end{verbatim}} \begin{verbatim} Assigning property Indices to a, b, c, d, e. Assigning property PartialDerivative to \partial, \nabla. Assigning property Depends to A, F. Assigning property Indices to a, b, c, d, e. Assigning property Accent to \delta. Assigning property AntiSymmetric to F. Assigning property KroneckerDelta to \delta. \end{verbatim} {\color[named]{Blue}\begin{verbatim} S:= -(1/4) F_{a b} F_{a b}; \end{verbatim}} % orig % (-1/4) F_{a b} F_{a b}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= (\frac{-1}{4})\, F_{a b} F_{a b}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( F_{a b} -> \partial_{a}{A_{b}} - \partial_{b}{A_{a}} ); \end{verbatim}} % orig % (-1/4) (\partial_{a}{A_{b}} - \partial_{b}{A_{a}}) (\partial_{a}{A_{b}} - \partial_{b}{A_{a}}); % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= (\frac{-1}{4})\, (\partial_{a}{A_{b}} - \partial_{b}{A_{a}}) (\partial_{a}{A_{b}} - \partial_{b}{A_{a}}); \end{dmath*} {\color[named]{Blue}\begin{verbatim} @distribute!(%); \end{verbatim}} % orig % - 1/4 \partial_{a}{A_{b}} \partial_{a}{A_{b}} + 1/4 \partial_{a}{A_{b}} \partial_{b}{A_{a}} + 1/4 \partial_{b}{A_{a}} \partial_{a}{A_{b}} - 1/4 \partial_{b}{A_{a}} \partial_{b}{A_{a}}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= - \frac{1}{4}\, \partial_{a}{A_{b}} \partial_{a}{A_{b}} + \frac{1}{4}\, \partial_{a}{A_{b}} \partial_{b}{A_{a}} + \frac{1}{4}\, \partial_{b}{A_{a}} \partial_{a}{A_{b}} - \frac{1}{4}\, \partial_{b}{A_{a}} \partial_{b}{A_{a}}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @vary!(%)( A_{b} -> \delta{A_{b}}); \end{verbatim}} % orig % - 1/4 \partial_{a}{\delta{A_{b}}} \partial_{a}{A_{b}} - 1/4 \partial_{a}{A_{b}} \partial_{a}{\delta{A_{b}}} + 1/4 \partial_{a}{\delta{A_{b}}} \partial_{b}{A_{a}} + 1/4 \partial_{a}{A_{b}} \partial_{b}{\delta{A_{a}}} + 1/4 \partial_{b}{\delta{A_{a}}} \partial_{a}{A_{b}} + 1/4 \partial_{b}{A_{a}} \partial_{a}{\delta{A_{b}}} - 1/4 \partial_{b}{\delta{A_{a}}} \partial_{b}{A_{a}} - 1/4 \partial_{b}{A_{a}} \partial_{b}{\delta{A_{a}}}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= - \frac{1}{4}\, \partial_{a}{\delta{A_{b}}} \partial_{a}{A_{b}} - \frac{1}{4}\, \partial_{a}{A_{b}} \partial_{a}{\delta{A_{b}}} + \frac{1}{4}\, \partial_{a}{\delta{A_{b}}} \partial_{b}{A_{a}} + \frac{1}{4}\, \partial_{a}{A_{b}} \partial_{b}{\delta{A_{a}}} + \frac{1}{4}\, \partial_{b}{\delta{A_{a}}} \partial_{a}{A_{b}} + \frac{1}{4}\, \partial_{b}{A_{a}} \partial_{a}{\delta{A_{b}}} - \frac{1}{4}\, \partial_{b}{\delta{A_{a}}} \partial_{b}{A_{a}} - \frac{1}{4}\, \partial_{b}{A_{a}} \partial_{b}{\delta{A_{a}}}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @prodsort!(%): @rename_dummies!(%): @collect_terms!(%); \end{verbatim}} % orig % - \partial_{a}{A_{b}} \partial_{a}{\delta{A_{b}}} + \partial_{a}{A_{b}} \partial_{b}{\delta{A_{a}}}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= - \partial_{a}{A_{b}} \partial_{a}{\delta{A_{b}}} + \partial_{a}{A_{b}} \partial_{b}{\delta{A_{a}}}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( \partial_{a}{\delta{A_{b}}} -> \nabla_{a}{\delta{A_{b}}} ); \end{verbatim}} % orig % - \partial_{a}{A_{b}} \nabla_{a}{\delta{A_{b}}} + \partial_{a}{A_{b}} \nabla_{b}{\delta{A_{a}}}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= - \partial_{a}{A_{b}} \nabla_{a}{\delta{A_{b}}} + \partial_{a}{A_{b}} \nabla_{b}{\delta{A_{a}}}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @pintegrate!(%)( \nabla ): @rename!(%){"\nabla"}{"\partial"}; \end{verbatim}} % orig % \partial_{a}{\partial_{a}{A_{b}}} \delta{A_{b}} - \partial_{b}{\partial_{a}{A_{b}}} \delta{A_{a}}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= \partial_{a}{\partial_{a}{A_{b}}} \delta{A_{b}} - \partial_{b}{\partial_{a}{A_{b}}} \delta{A_{a}}; \end{dmath*} \end{document} cadabra-1.39/examples/simple_clifford.cnb000066400000000000000000000043711234107666300205030ustar00rootroot00000000000000% Cadabra notebook version 1.0 \documentclass[11pt]{article} \usepackage[textwidth=460pt, textheight=660pt]{geometry} \usepackage[usenames]{color} \usepackage[parfill]{parskip} \usepackage{breqn} \def\specialcolon{\mathrel{\mathop{:}}\hspace{-.5em}} \renewcommand{\bar}[1]{\overline{#1}} \begin{document} % Begin TeX cell closed {\large\bfseries Some simple gamma matrix algebra.} % End TeX cell {\color[named]{Blue}\begin{verbatim} ::PostDefaultRules( @@prodsort!(%), @@eliminate_kr!(%), @@canonicalise!(%), @@collect_terms!(%) ). \end{verbatim}} \begin{verbatim} Assigning property PostDefaultRules to . \end{verbatim} {\color[named]{Blue}\begin{verbatim} {s,r,l,k,m,n}::Indices(vector). {s,r,l,k,m,n}::Integer(0..d-1). \Gamma_{#}::GammaMatrix(metric=\delta). \delta_{m n}::KroneckerDelta. \end{verbatim}} \begin{verbatim} Assigning property Indices to s, r, l, k, m, n. Assigning property Integer to s, r, l, k, m, n. Assigning property GammaMatrix to \Gamma. Assigning property KroneckerDelta to \delta. \end{verbatim} % Begin TeX cell closed The expression which we want to simplify: % End TeX cell {\color[named]{Blue}\begin{verbatim} \Gamma_{s r} \Gamma_{r l} \Gamma_{k m} \Gamma_{m s}; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 1\specialcolon{}= (-1)\, \Gamma_{m r} \Gamma_{l m} \Gamma_{k s} \Gamma_{r s}; \end{dmath*} % Begin TeX cell closed By twice joining adjacent gamma matrices, we join the first and second and third and fourth factor: % End TeX cell {\color[named]{Blue}\begin{verbatim} @join!(%){expand}: @join!(%){expand}; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 1\specialcolon{}= (-1)\, (2\, \Gamma_{l r} - \Gamma_{l r} d + \delta_{l r} d - \delta_{l r}) (2\, \Gamma_{k r} - \Gamma_{k r} d + \delta_{k r} - \delta_{k r} d); \end{dmath*} % Begin TeX cell closed After distributing the result and joining once more, we collect factors and get the desired result: % End TeX cell {\color[named]{Blue}\begin{verbatim} @distribute!(%): @canonicalise!(%): @join!(%){expand}: @distribute!(%): @factorise!(%){d}: @collect_factors!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] 1\specialcolon{}= \Gamma_{k l} (12 - 18\, d + 8\, d**2 - d**3) + \delta_{k l} ( - 3 + 6\, d - 4\, d**2 + d**3); \end{dmath*} \end{document} cadabra-1.39/examples/supergravity.cnb000066400000000000000000002432651234107666300201150ustar00rootroot00000000000000% Cadabra notebook version 1.1 \documentclass[11pt]{article} \usepackage[textwidth=460pt, textheight=660pt]{geometry} \usepackage[usenames]{color} \usepackage{amssymb} \usepackage[parfill]{parskip} \usepackage{breqn} \usepackage{tableaux} \def\specialcolon{\mathrel{\mathop{:}}\hspace{-.5em}} \renewcommand{\bar}[1]{\overline{#1}} \begin{document} % Begin TeX cell closed {\large\bfseries Superinvariance of four-dimensional $N=1$ supergravity.} This notebook follows the notation and conventions of P. van Nieuwenhuizen, ``Supergravity'', Phys.~Rep.~68 (1981) 189, except for $\gamma_5$ which is always written using the product of four gamma matrices. We will use the 1.5 order formalism as described in section 1.6 and~1.7. \emph{Note: not completely updated to current cadabra status.} % End TeX cell {\color[named]{Blue}\begin{verbatim} ::PostDefaultRules( @@eliminate_kr!(%), @@prodsort!(%), @@collect_terms!(%) ). \end{verbatim}} % Begin TeX comment Assigning property PostDefaultRules. \\ % End TeX comment % Begin TeX cell closed Declaration of derivative operators and Dirac conjugation: % End TeX cell {\color[named]{Blue}\begin{verbatim} D{#}::Derivative. \bar{#}::DiracBar. \partial{#}::PartialDerivative. \delta{A??}::Derivative. \end{verbatim}} % Begin TeX comment Assigning property Derivative to $D{\#}$. \\ % End TeX comment % Begin TeX comment Assigning property DiracBar to $\bar{\#}$. \\ % End TeX comment % Begin TeX comment Assigning property PartialDerivative to $\partial{\#}$. \\ % End TeX comment % Begin TeX comment Assigning property Derivative to $\delta{A??}$. \\ % End TeX comment % Begin TeX cell closed Indices for flat and curved space: % End TeX cell {\color[named]{Blue}\begin{verbatim} {m,n,p,q,r,s,t,u,m#}::Indices(flat). {m,n,p,q,r,s,t,u,m#}::Integer(0..3). {\mu,\nu,\rho,\sigma,\kappa,\lambda,\alpha,\beta,\gamma}::Indices(curved,position=fixed). {\mu,\nu,\rho,\sigma,\kappa,\lambda,\alpha,\beta,\gamma}::Integer(0..3). \end{verbatim}} % Begin TeX comment Assigning list property Indices to $\{m,\; n,\; p,\; q,\; r,\; s,\; t,\; u,\; m\#\}$. \\ % End TeX comment % Begin TeX comment Assigning property Integer to $m$, $n$, $p$, $q$, $r$, $s$, $t$, $u$, $m\#$. \\ % End TeX comment % Begin TeX comment Assigning list property Indices to $\{\mu,\; \nu,\; \rho,\; \sigma,\; \kappa,\; \lambda,\; \alpha,\; \beta,\; \gamma\}$. \\ % End TeX comment % Begin TeX comment Assigning property Integer to $\mu$, $\nu$, $\rho$, $\sigma$, $\kappa$, $\lambda$, $\alpha$, $\beta$, $\gamma$. \\ % End TeX comment % Begin TeX cell closed Declaration of all bosonic fields: % End TeX cell {\color[named]{Blue}\begin{verbatim} e^{m \mu}::Vielbein. e_{m \mu}::InverseVielbein. g^{\mu\nu}::InverseMetric. g_{\mu\nu}::Metric. \omega_{\mu m n}::TableauSymmetry( indices={1,2}, shape={1,1} ). \delta_{\mu}^{\rho}::KroneckerDelta. \delta^{\mu}_{\rho}::KroneckerDelta. \delta^{m n}::KroneckerDelta. R_{\mu\nu m n}::TableauSymmetry( indices={0,1}, shape={1,1}, indices={2,3}, shape={1,1} ). { e^{m \mu}, e_{m \mu}, e, T^{\mu}_{\nu\rho} }::Depends(\partial, D). T^{\mu}_{\nu\rho}::TableauSymmetry( indices={1,2}, shape={1,1} ). \epsilon_{m n p q}::AntiSymmetric. \epsilon^{\mu\nu\rho\sigma}::AntiSymmetric. \end{verbatim}} % Begin TeX comment Assigning property Vielbein to ${e}^{m \mu}$. \\ % End TeX comment % Begin TeX comment Assigning property InverseVielbein to ${e}_{m \mu}$. \\ % End TeX comment % Begin TeX comment Assigning property InverseMetric to ${g}^{\mu \nu}$. \\ % End TeX comment % Begin TeX comment Assigning property Metric to ${g}_{\mu \nu}$. \\ % End TeX comment % Begin TeX comment Assigning property TableauSymmetry to ${\omega}_{\mu m n}$. \\ % End TeX comment % Begin TeX comment Assigning property KroneckerDelta to ${\delta}_{\mu}\,^{\rho}$. \\ % End TeX comment % Begin TeX comment Assigning property KroneckerDelta to ${\delta}^{\mu}\,_{\rho}$. \\ % End TeX comment % Begin TeX comment Assigning property KroneckerDelta to ${\delta}^{m n}$. \\ % End TeX comment % Begin TeX comment Assigning property TableauSymmetry to ${R}_{\mu \nu m n}$. \\ % End TeX comment % Begin TeX comment Assigning property Depends to ${e}^{m \mu}$, ${e}_{m \mu}$, $e$, ${T}^{\mu}\,_{\nu \rho}$. \\ % End TeX comment % Begin TeX comment Assigning property TableauSymmetry to ${T}^{\mu}\,_{\nu \rho}$. \\ % End TeX comment % Begin TeX comment Assigning property AntiSymmetric to ${\epsilon}_{m n p q}$. \\ % End TeX comment % Begin TeX comment Assigning property AntiSymmetric to ${\epsilon}^{\mu \nu \rho \sigma}$. \\ % End TeX comment % Begin TeX cell closed Declaration of all fermionic fields: % End TeX cell {\color[named]{Blue}\begin{verbatim} { \epsilon,\psi_{\mu},\psi_{\mu\nu} }::Spinor(dimension=4, type=Majorana). \Gamma_{#{m}}::GammaMatrix(metric=\delta). \Gamma_{#{\mu}}::GammaMatrix(metric=g). \Gamma_{#}::GammaMatrix. { \psi_{\mu\nu}, \psi_{\mu}, \epsilon }::AntiCommuting. { \psi_{\mu}, \psi_{\mu\nu} }::SelfAntiCommuting. { \epsilon, \psi_{\mu}, \psi_{\mu\nu} }::SortOrder. { \epsilon, \psi_{\mu}, \psi_{\mu\nu} }::Depends(\bar,\partial,D). \Gamma_{#}::Depends(\bar). \psi_{\mu\nu}::AntiSymmetric. \end{verbatim}} % Begin TeX comment Assigning property Spinor to $\epsilon$, ${\psi}_{\mu}$, ${\psi}_{\mu \nu}$. \\ % End TeX comment % Begin TeX comment Assigning property GammaMatrix to ${\Gamma}_{\#{m}}$. \\ % End TeX comment % Begin TeX comment Assigning property GammaMatrix to ${\Gamma}_{\#{\mu}}$. \\ % End TeX comment % Begin TeX comment Assigning property GammaMatrix to ${\Gamma}_{\#}$. \\ % End TeX comment % Begin TeX comment Assigning list property AntiCommuting to $\{{\psi}_{\mu \nu},\; {\psi}_{\mu},\; \epsilon\}$. \\ % End TeX comment % Begin TeX comment Assigning property SelfAntiCommuting to ${\psi}_{\mu}$, ${\psi}_{\mu \nu}$. \\ % End TeX comment % Begin TeX comment Assigning list property SortOrder to $\{\epsilon,\; {\psi}_{\mu},\; {\psi}_{\mu \nu}\}$. \\ % End TeX comment % Begin TeX comment Assigning property Depends to $\epsilon$, ${\psi}_{\mu}$, ${\psi}_{\mu \nu}$. \\ % End TeX comment % Begin TeX comment Assigning property Depends to ${\Gamma}_{\#}$. \\ % End TeX comment % Begin TeX comment Assigning property AntiSymmetric to ${\psi}_{\mu \nu}$. \\ % End TeX comment % Begin TeX cell closed The Lagrangian of $N=1$ four-dimensionsal supergravity, % End TeX cell {\color[named]{Blue}\begin{verbatim} L:= -1/2 e e^{n \nu} e^{m \mu} R_{\mu\nu n m} - 1/2 e \bar{\psi_\mu} \Gamma^{\mu\nu\rho} D_{\nu}{\psi_{\rho}}; \end{verbatim}} % orig % - 1/2 R_{\mu \nu n m} e e^{m \mu} e^{n \nu} - 1/2 \bar{\psi_{\mu}} \Gamma^{\mu \nu \rho} D_{\nu}{\psi_{\rho}} e % end_orig \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= - \frac{1}{2}\, {R}_{\mu \nu n m} e {e}^{m \mu} {e}^{n \nu} - \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu \nu \rho} {D}_{\nu}{{\psi}_{\rho}} e; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @rewrite_indices!(%){ \Gamma^{m n p} }{ e^{n \mu} }; \end{verbatim}} % orig % - 1/2 R_{\mu \nu n m} e e^{m \mu} e^{n \nu} - 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} e e^{m \mu} e^{n \nu} e^{p \rho} % end_orig \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= - \frac{1}{2}\, {R}_{\mu \nu n m} e {e}^{m \mu} {e}^{n \nu} - \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho}; \end{dmath*} % Begin TeX cell closed This action is supposed to be invariant under the following supersymmetry transformation rules: % End TeX cell {\color[named]{Blue}\begin{verbatim} susy:= { e^{n \mu} -> -\bar{\epsilon} \Gamma^m \psi_\nu e^{m \mu} e^{n \nu}, e -> e \bar{\epsilon} \Gamma^n \psi_\mu e^{n\mu}, \psi_\mu -> D_{\mu}{\epsilon} }; \end{verbatim}} % orig % \{e^{n \mu} -> (-1) \bar{\epsilon} \Gamma^{m} \psi_{\nu} e^{m \mu} e^{n \nu}, e -> \bar{\epsilon} \Gamma^{n} \psi_{\mu} e e^{n \mu}, \psi_{\mu} -> D_{\mu}{\epsilon}\} % end_orig \begin{dmath*}[compact, spread=2pt] susy\specialcolon{}= \{{e}^{n \mu} \rightarrow (-1)\, \bar{\epsilon} {\Gamma}^{m} {\psi}_{\nu} {e}^{m \mu} {e}^{n \nu},\; e \rightarrow \bar{\epsilon} {\Gamma}^{n} {\psi}_{\mu} e {e}^{n \mu},\; {\psi}_{\mu} \rightarrow {D}_{\mu}{\epsilon}\}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @vary!(L)( @(susy) ); \end{verbatim}} % orig % - 1/2 R_{\mu \nu n m} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e e^{m \mu} e^{n \nu} e^{p \rho} + 1/2 R_{\mu \nu n m} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e e^{m \rho} e^{n \nu} e^{p \mu} + 1/2 R_{\mu \nu n m} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e e^{m \mu} e^{n \rho} e^{p \nu} - 1/2 \bar{D_{\mu}{\epsilon}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} e e^{m \mu} e^{n \nu} e^{p \rho} - 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{D_{\rho}{\epsilon}} e e^{m \mu} e^{n \nu} e^{p \rho} - 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \rho} e^{q \sigma} + 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \sigma} e^{n \nu} e^{p \rho} e^{q \mu} + 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \sigma} e^{p \rho} e^{q \nu} + 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \sigma} e^{q \rho} % end_orig \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= - \frac{1}{2}\, {R}_{\mu \nu n m} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\rho} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} + \frac{1}{2}\, {R}_{\mu \nu n m} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\rho} e {e}^{m \rho} {e}^{n \nu} {e}^{p \mu} + \frac{1}{2}\, {R}_{\mu \nu n m} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\rho} e {e}^{m \mu} {e}^{n \rho} {e}^{p \nu} - \frac{1}{2}\, \bar{{D}_{\mu}{\epsilon}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} - \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{D}_{\rho}{\epsilon}} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} - \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} {e}^{q \sigma} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \sigma} {e}^{n \nu} {e}^{p \rho} {e}^{q \mu} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \mu} {e}^{n \sigma} {e}^{p \rho} {e}^{q \nu} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \mu} {e}^{n \nu} {e}^{p \sigma} {e}^{q \rho}; \end{dmath*} % Begin TeX cell closed The $D_\nu D_\rho \epsilon$ factor can be rewritten as a Riemann tensor, % End TeX cell {\color[named]{Blue}\begin{verbatim} @substitute!(%)( D_{\nu}{ D_{\rho}{ \epsilon } } -> 1/4 R_{\nu\rho m n} \Gamma^{m n} \epsilon): @prodsort!(%); \end{verbatim}} % Begin TeX comment @prodsort: not applicable. % End TeX comment % orig % - 1/2 R_{\mu \nu n m} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e e^{m \mu} e^{n \nu} e^{p \rho} + 1/2 R_{\mu \nu n m} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e e^{m \rho} e^{n \nu} e^{p \mu} + 1/2 R_{\mu \nu n m} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e e^{m \mu} e^{n \rho} e^{p \nu} - 1/2 \bar{D_{\mu}{\epsilon}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} e e^{m \mu} e^{n \nu} e^{p \rho} - 1/8 R_{\nu \rho q r} \bar{\psi_{\mu}} \Gamma^{m n p} \Gamma^{q r} \epsilon e e^{m \mu} e^{n \nu} e^{p \rho} - 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \rho} e^{q \sigma} + 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \sigma} e^{n \nu} e^{p \rho} e^{q \mu} + 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \sigma} e^{p \rho} e^{q \nu} + 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \sigma} e^{q \rho} % end_orig \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= - \frac{1}{2}\, {R}_{\mu \nu n m} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\rho} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} + \frac{1}{2}\, {R}_{\mu \nu n m} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\rho} e {e}^{m \rho} {e}^{n \nu} {e}^{p \mu} + \frac{1}{2}\, {R}_{\mu \nu n m} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\rho} e {e}^{m \mu} {e}^{n \rho} {e}^{p \nu} - \frac{1}{2}\, \bar{{D}_{\mu}{\epsilon}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} - \frac{1}{8}\, {R}_{\nu \rho q r} \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {\Gamma}^{q r} \epsilon e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} - \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} {e}^{q \sigma} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \sigma} {e}^{n \nu} {e}^{p \rho} {e}^{q \mu} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \mu} {e}^{n \sigma} {e}^{p \rho} {e}^{q \nu} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \mu} {e}^{n \nu} {e}^{p \sigma} {e}^{q \rho}; \end{dmath*} % Begin TeX cell closed The $\overline{D_{\mu}{\epsilon}}$ term needs to be partially integrated. We isolate it and then take the covariant derivative apart. % End TeX cell {\color[named]{Blue}\begin{verbatim} deps:=@take_match![@(L)]( \bar{D_{\mu}{\epsilon}}*A?? ); \end{verbatim}} % orig % (-1/2) \bar{D_{\mu}{\epsilon}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} e e^{m \mu} e^{n \nu} e^{p \rho} % end_orig \begin{dmath*}[compact, spread=2pt] deps\specialcolon{}= (\frac{-1}{2})\, \bar{{D}_{\mu}{\epsilon}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( \bar{D_{\mu}{\epsilon}} -> \partial_{\mu}{\bar{\epsilon}} - 1/4 \bar{\epsilon}\omega_{\mu m n} \Gamma^{m n} ): @distribute!(%); \end{verbatim}} % orig % - 1/2 \partial_{\mu}{\bar{\epsilon}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} e e^{m \mu} e^{n \nu} e^{p \rho} + 1/8 \bar{\epsilon} \Gamma^{q r} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \omega_{\mu q r} e e^{m \mu} e^{n \nu} e^{p \rho} % end_orig \begin{dmath*}[compact, spread=2pt] deps\specialcolon{}= - \frac{1}{2}\, {\partial}_{\mu}{\bar{\epsilon}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} + \frac{1}{8}\, \bar{\epsilon} {\Gamma}^{q r} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} {\omega}_{\mu q r} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @pintegrate!(%)(\partial): @prodrule!(%): @distribute!(%): @unwrap!(%); \end{verbatim}} % orig % 1/2 \bar{\epsilon} \Gamma^{m n p} \partial_{\mu}{D_{\nu}{\psi_{\rho}}} e e^{m \mu} e^{n \nu} e^{p \rho} + 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \partial_{\mu}{e} e^{m \mu} e^{n \nu} e^{p \rho} + 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \partial_{\mu}{e^{m \mu}} e e^{n \nu} e^{p \rho} + 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \partial_{\mu}{e^{n \nu}} e e^{m \mu} e^{p \rho} + 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \partial_{\mu}{e^{p \rho}} e e^{m \mu} e^{n \nu} + 1/8 \bar{\epsilon} \Gamma^{q r} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \omega_{\mu q r} e e^{m \mu} e^{n \nu} e^{p \rho} % end_orig \begin{dmath*}[compact, spread=2pt] deps\specialcolon{}= \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {\partial}_{\mu}{{D}_{\nu}{{\psi}_{\rho}}} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} + \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} {\partial}_{\mu}{e} {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} + \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} {\partial}_{\mu}{{e}^{m \mu}} e {e}^{n \nu} {e}^{p \rho} + \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} {\partial}_{\mu}{{e}^{n \nu}} e {e}^{m \mu} {e}^{p \rho} + \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} {\partial}_{\mu}{{e}^{p \rho}} e {e}^{m \mu} {e}^{n \nu} + \frac{1}{8}\, \bar{\epsilon} {\Gamma}^{q r} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} {\omega}_{\mu q r} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( \Gamma^{q r}\Gamma^{m n p} -> - @join![ \Gamma^{m n p} \Gamma^{q r} - \Gamma^{q r} \Gamma^{m n p} ]{expand} ); \end{verbatim}} % orig % 1/2 \bar{\epsilon} \Gamma^{m n p} \partial_{\mu}{D_{\nu}{\psi_{\rho}}} e e^{m \mu} e^{n \nu} e^{p \rho} + 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \partial_{\mu}{e} e^{m \mu} e^{n \nu} e^{p \rho} + 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \partial_{\mu}{e^{m \mu}} e e^{n \nu} e^{p \rho} + 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \partial_{\mu}{e^{n \nu}} e e^{m \mu} e^{p \rho} + 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \partial_{\mu}{e^{p \rho}} e e^{m \mu} e^{n \nu} + 1/8 \bar{\epsilon} ( - \Gamma^{m n r} \delta^{p q} + \Gamma^{m n q} \delta^{p r} + \Gamma^{m p r} \delta^{n q} - \Gamma^{m p q} \delta^{n r} - \Gamma^{n p r} \delta^{m q} + \Gamma^{n p q} \delta^{m r} + \Gamma^{q n p} \delta^{m r} - \Gamma^{q n m} \delta^{p r} + \Gamma^{q p m} \delta^{n r} - \Gamma^{r n p} \delta^{m q} + \Gamma^{r n m} \delta^{p q} - \Gamma^{r p m} \delta^{n q}) D_{\nu}{\psi_{\rho}} \omega_{\mu q r} e e^{m \mu} e^{n \nu} e^{p \rho} % end_orig \begin{dmath*}[compact, spread=2pt] deps\specialcolon{}= \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {\partial}_{\mu}{{D}_{\nu}{{\psi}_{\rho}}} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} + \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} {\partial}_{\mu}{e} {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} + \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} {\partial}_{\mu}{{e}^{m \mu}} e {e}^{n \nu} {e}^{p \rho} + \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} {\partial}_{\mu}{{e}^{n \nu}} e {e}^{m \mu} {e}^{p \rho} + \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} {\partial}_{\mu}{{e}^{p \rho}} e {e}^{m \mu} {e}^{n \nu} + \frac{1}{8}\, \bar{\epsilon} ( - {\Gamma}^{m n r} {\delta}^{p q} + {\Gamma}^{m n q} {\delta}^{p r} + {\Gamma}^{m p r} {\delta}^{n q} - {\Gamma}^{m p q} {\delta}^{n r} - {\Gamma}^{n p r} {\delta}^{m q} + {\Gamma}^{n p q} {\delta}^{m r} + {\Gamma}^{q n p} {\delta}^{m r} - {\Gamma}^{q n m} {\delta}^{p r} + {\Gamma}^{q p m} {\delta}^{n r} - {\Gamma}^{r n p} {\delta}^{m q} + {\Gamma}^{r n m} {\delta}^{p q} - {\Gamma}^{r p m} {\delta}^{n q}) {D}_{\nu}{{\psi}_{\rho}} {\omega}_{\mu q r} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @distribute!(%): @canonicalise!(%): @rename_dummies!(%): @substitute!(%)( \partial_{\mu}{D_{\nu}{\psi_{\rho}}} -> 1/4 R_{\mu\nu m n}\Gamma^{m n} \psi_{\rho} ); \end{verbatim}} % orig % 1/8 R_{\mu \nu q r} \bar{\epsilon} \Gamma^{m n p} \Gamma^{q r} \psi_{\rho} e e^{m \mu} e^{n \nu} e^{p \rho} + 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \partial_{\rho}{e} e^{m \mu} e^{n \nu} e^{p \rho} + 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \partial_{\rho}{e^{m \rho}} e e^{n \mu} e^{p \nu} + 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \partial_{\rho}{e^{m \mu}} e e^{n \nu} e^{p \rho} - 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \partial_{\rho}{e^{m \nu}} e e^{n \mu} e^{p \rho} - 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \omega_{\rho}^{m}_{q} e e^{n \mu} e^{p \rho} e^{q \nu} + 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \omega_{\rho}^{m}_{q} e e^{n \nu} e^{p \rho} e^{q \mu} + 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \omega_{\rho}^{m}_{q} e e^{n \mu} e^{p \nu} e^{q \rho} % end_orig \begin{dmath*}[compact, spread=2pt] deps\specialcolon{}= \frac{1}{8}\, {R}_{\mu \nu q r} \bar{\epsilon} {\Gamma}^{m n p} {\Gamma}^{q r} {\psi}_{\rho} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} + \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} {\partial}_{\rho}{e} {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} + \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} {\partial}_{\rho}{{e}^{m \rho}} e {e}^{n \mu} {e}^{p \nu} + \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} {\partial}_{\rho}{{e}^{m \mu}} e {e}^{n \nu} {e}^{p \rho} - \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} {\partial}_{\rho}{{e}^{m \nu}} e {e}^{n \mu} {e}^{p \rho} - \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} {\omega}_{\rho}\,^{m}\,_{q} e {e}^{n \mu} {e}^{p \rho} {e}^{q \nu} + \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} {\omega}_{\rho}\,^{m}\,_{q} e {e}^{n \nu} {e}^{p \rho} {e}^{q \mu} + \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} {\omega}_{\rho}\,^{m}\,_{q} e {e}^{n \mu} {e}^{p \nu} {e}^{q \rho}; \end{dmath*} % Begin TeX cell closed This now needs to be rewritten in terms of the torsion, and then the torsion is to be replaced with a fermi bilinear. % End TeX cell {\color[named]{Blue}\begin{verbatim} @substitute!(%)( \partial_{\rho}{e} -> - e e_{n \mu} \partial_{\rho}{ e^{n \mu} } ); \end{verbatim}} % orig % 1/8 R_{\mu \nu q r} \bar{\epsilon} \Gamma^{m n p} \Gamma^{q r} \psi_{\rho} e e^{m \mu} e^{n \nu} e^{p \rho} - 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \partial_{\rho}{e^{q \sigma}} e e_{q \sigma} e^{m \mu} e^{n \nu} e^{p \rho} + 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \partial_{\rho}{e^{m \rho}} e e^{n \mu} e^{p \nu} + 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \partial_{\rho}{e^{m \mu}} e e^{n \nu} e^{p \rho} - 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \partial_{\rho}{e^{m \nu}} e e^{n \mu} e^{p \rho} - 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \omega_{\rho}^{m}_{q} e e^{n \mu} e^{p \rho} e^{q \nu} + 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \omega_{\rho}^{m}_{q} e e^{n \nu} e^{p \rho} e^{q \mu} + 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \omega_{\rho}^{m}_{q} e e^{n \mu} e^{p \nu} e^{q \rho} % end_orig \begin{dmath*}[compact, spread=2pt] deps\specialcolon{}= \frac{1}{8}\, {R}_{\mu \nu q r} \bar{\epsilon} {\Gamma}^{m n p} {\Gamma}^{q r} {\psi}_{\rho} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} - \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} {\partial}_{\rho}{{e}^{q \sigma}} e {e}_{q \sigma} {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} + \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} {\partial}_{\rho}{{e}^{m \rho}} e {e}^{n \mu} {e}^{p \nu} + \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} {\partial}_{\rho}{{e}^{m \mu}} e {e}^{n \nu} {e}^{p \rho} - \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} {\partial}_{\rho}{{e}^{m \nu}} e {e}^{n \mu} {e}^{p \rho} - \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} {\omega}_{\rho}\,^{m}\,_{q} e {e}^{n \mu} {e}^{p \rho} {e}^{q \nu} + \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} {\omega}_{\rho}\,^{m}\,_{q} e {e}^{n \nu} {e}^{p \rho} {e}^{q \mu} + \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} {\omega}_{\rho}\,^{m}\,_{q} e {e}^{n \mu} {e}^{p \nu} {e}^{q \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( \partial_{\mu}{e^{m \nu}} -> -\omega_{\mu m n} e^{n \nu} - C^{\nu}_{\mu\rho} e^{m \rho} ): @distribute!(%); \end{verbatim}} % orig % 1/8 R_{\mu \nu q r} \bar{\epsilon} \Gamma^{m n p} \Gamma^{q r} \psi_{\rho} e e^{m \mu} e^{n \nu} e^{p \rho} + 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} \omega_{\rho q r} e e_{q \sigma} e^{m \mu} e^{n \nu} e^{p \rho} e^{r \sigma} + 1/2 C^{\sigma}_{\rho \kappa} \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} e e_{q \sigma} e^{m \mu} e^{n \nu} e^{p \rho} e^{q \kappa} - 1/2 C^{\rho}_{\rho \sigma} \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} e e^{m \sigma} e^{n \mu} e^{p \nu} - 1/2 C^{\mu}_{\rho \sigma} \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} e e^{m \sigma} e^{n \nu} e^{p \rho} + 1/2 C^{\nu}_{\rho \sigma} \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} e e^{m \sigma} e^{n \mu} e^{p \rho} % end_orig \begin{dmath*}[compact, spread=2pt] deps\specialcolon{}= \frac{1}{8}\, {R}_{\mu \nu q r} \bar{\epsilon} {\Gamma}^{m n p} {\Gamma}^{q r} {\psi}_{\rho} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} + \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} {\omega}_{\rho q r} e {e}_{q \sigma} {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} {e}^{r \sigma} + \frac{1}{2}\, {C}^{\sigma}\,_{\rho \kappa} \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} e {e}_{q \sigma} {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} {e}^{q \kappa} - \frac{1}{2}\, {C}^{\rho}\,_{\rho \sigma} \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} e {e}^{m \sigma} {e}^{n \mu} {e}^{p \nu} - \frac{1}{2}\, {C}^{\mu}\,_{\rho \sigma} \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} e {e}^{m \sigma} {e}^{n \nu} {e}^{p \rho} + \frac{1}{2}\, {C}^{\nu}\,_{\rho \sigma} \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} e {e}^{m \sigma} {e}^{n \mu} {e}^{p \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( e_{q \sigma} e^{q \kappa} -> \delta_{\sigma}^{\kappa}, e_{q \sigma} e^{r \sigma} -> \delta^{q r} ): @canonicalise!(%): @rename_dummies!(%); \end{verbatim}} % orig % 1/8 R_{\mu \nu m n} \bar{\epsilon} \Gamma^{p q r} \Gamma^{m n} \psi_{\rho} e e^{p \mu} e^{q \nu} e^{r \rho} + 1/2 C^{\mu}_{\nu \mu} \bar{\epsilon} \Gamma^{m n p} D_{\rho}{\psi_{\sigma}} e e^{m \nu} e^{n \rho} e^{p \sigma} - 1/2 C^{\mu}_{\mu \nu} \bar{\epsilon} \Gamma^{m n p} D_{\rho}{\psi_{\sigma}} e e^{m \nu} e^{n \rho} e^{p \sigma} - 1/2 C^{\mu}_{\nu \rho} \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\sigma}} e e^{m \nu} e^{n \rho} e^{p \sigma} + 1/2 C^{\mu}_{\nu \rho} \bar{\epsilon} \Gamma^{m n p} D_{\sigma}{\psi_{\mu}} e e^{m \nu} e^{n \rho} e^{p \sigma} % end_orig \begin{dmath*}[compact, spread=2pt] deps\specialcolon{}= \frac{1}{8}\, {R}_{\mu \nu m n} \bar{\epsilon} {\Gamma}^{p q r} {\Gamma}^{m n} {\psi}_{\rho} e {e}^{p \mu} {e}^{q \nu} {e}^{r \rho} + \frac{1}{2}\, {C}^{\mu}\,_{\nu \mu} \bar{\epsilon} {\Gamma}^{m n p} {D}_{\rho}{{\psi}_{\sigma}} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} - \frac{1}{2}\, {C}^{\mu}\,_{\mu \nu} \bar{\epsilon} {\Gamma}^{m n p} {D}_{\rho}{{\psi}_{\sigma}} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} - \frac{1}{2}\, {C}^{\mu}\,_{\nu \rho} \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\sigma}} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} + \frac{1}{2}\, {C}^{\mu}\,_{\nu \rho} \bar{\epsilon} {\Gamma}^{m n p} {D}_{\sigma}{{\psi}_{\mu}} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( C^{\mu}_{\nu\kappa} -> 1/2 C^{\mu}_{\nu\kappa} + 1/2 C^{\mu}_{\kappa\nu} + T^{\mu}_{\nu\kappa} ): @distribute!(%): @canonicalise!(%); \end{verbatim}} % orig % 1/8 R_{\mu \nu m n} \bar{\epsilon} \Gamma^{p q r} \Gamma^{m n} \psi_{\rho} e e^{p \mu} e^{q \nu} e^{r \rho} - \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} T^{\rho}_{\rho \sigma} e e^{m \mu} e^{n \nu} e^{p \sigma} - 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} T^{\mu}_{\rho \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} + 1/2 \bar{\epsilon} \Gamma^{m n p} D_{\mu}{\psi_{\nu}} T^{\nu}_{\rho \sigma} e e^{m \mu} e^{n \rho} e^{p \sigma} % end_orig \begin{dmath*}[compact, spread=2pt] deps\specialcolon{}= \frac{1}{8}\, {R}_{\mu \nu m n} \bar{\epsilon} {\Gamma}^{p q r} {\Gamma}^{m n} {\psi}_{\rho} e {e}^{p \mu} {e}^{q \nu} {e}^{r \rho} - \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} {T}^{\rho}\,_{\rho \sigma} e {e}^{m \mu} {e}^{n \nu} {e}^{p \sigma} - \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} {T}^{\mu}\,_{\rho \sigma} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} + \frac{1}{2}\, \bar{\epsilon} {\Gamma}^{m n p} {D}_{\mu}{{\psi}_{\nu}} {T}^{\nu}\,_{\rho \sigma} e {e}^{m \mu} {e}^{n \rho} {e}^{p \sigma}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( D_{\mu}{\psi_{\sigma}} -> 1/2 D_{\mu}{\psi_{\sigma}} + 1/2 D_{\sigma}{\psi_{\mu}} + \psi_{\mu\sigma} ): @distribute!(%): @canonicalise!(%); \end{verbatim}} % orig % 1/8 R_{\mu \nu m n} \bar{\epsilon} \Gamma^{p q r} \Gamma^{m n} \psi_{\rho} e e^{p \mu} e^{q \nu} e^{r \rho} - T^{\mu}_{\mu \nu} \bar{\epsilon} \Gamma^{m n p} \psi_{\rho \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} - T^{\mu}_{\nu \rho} \bar{\epsilon} \Gamma^{m n p} \psi_{\mu \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} % end_orig \begin{dmath*}[compact, spread=2pt] deps\specialcolon{}= \frac{1}{8}\, {R}_{\mu \nu m n} \bar{\epsilon} {\Gamma}^{p q r} {\Gamma}^{m n} {\psi}_{\rho} e {e}^{p \mu} {e}^{q \nu} {e}^{r \rho} - {T}^{\mu}\,_{\mu \nu} \bar{\epsilon} {\Gamma}^{m n p} {\psi}_{\rho \sigma} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} - {T}^{\mu}\,_{\nu \rho} \bar{\epsilon} {\Gamma}^{m n p} {\psi}_{\mu \sigma} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma}; \end{dmath*} % Begin TeX cell closed Put this back into the main variation and continue... % End TeX cell {\color[named]{Blue}\begin{verbatim} @replace_match!(L)( \bar{D_{\mu}{\epsilon}}*A?? -> @(deps) ); \end{verbatim}} % orig % - 1/2 R_{\mu \nu n m} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e e^{m \mu} e^{n \nu} e^{p \rho} + 1/2 R_{\mu \nu n m} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e e^{m \rho} e^{n \nu} e^{p \mu} + 1/2 R_{\mu \nu n m} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e e^{m \mu} e^{n \rho} e^{p \nu} + 1/8 R_{\mu \nu m n} \bar{\epsilon} \Gamma^{p q r} \Gamma^{m n} \psi_{\rho} e e^{p \mu} e^{q \nu} e^{r \rho} - T^{\mu}_{\mu \nu} \bar{\epsilon} \Gamma^{m n p} \psi_{\rho \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} - T^{\mu}_{\nu \rho} \bar{\epsilon} \Gamma^{m n p} \psi_{\mu \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} - 1/8 R_{\nu \rho q r} \bar{\psi_{\mu}} \Gamma^{m n p} \Gamma^{q r} \epsilon e e^{m \mu} e^{n \nu} e^{p \rho} - 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \rho} e^{q \sigma} + 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \sigma} e^{n \nu} e^{p \rho} e^{q \mu} + 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \sigma} e^{p \rho} e^{q \nu} + 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \sigma} e^{q \rho} % end_orig \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= - \frac{1}{2}\, {R}_{\mu \nu n m} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\rho} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} + \frac{1}{2}\, {R}_{\mu \nu n m} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\rho} e {e}^{m \rho} {e}^{n \nu} {e}^{p \mu} + \frac{1}{2}\, {R}_{\mu \nu n m} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\rho} e {e}^{m \mu} {e}^{n \rho} {e}^{p \nu} + \frac{1}{8}\, {R}_{\mu \nu m n} \bar{\epsilon} {\Gamma}^{p q r} {\Gamma}^{m n} {\psi}_{\rho} e {e}^{p \mu} {e}^{q \nu} {e}^{r \rho} - {T}^{\mu}\,_{\mu \nu} \bar{\epsilon} {\Gamma}^{m n p} {\psi}_{\rho \sigma} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} - {T}^{\mu}\,_{\nu \rho} \bar{\epsilon} {\Gamma}^{m n p} {\psi}_{\mu \sigma} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} - \frac{1}{8}\, {R}_{\nu \rho q r} \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {\Gamma}^{q r} \epsilon e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} - \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} {e}^{q \sigma} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \sigma} {e}^{n \nu} {e}^{p \rho} {e}^{q \mu} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \mu} {e}^{n \sigma} {e}^{p \rho} {e}^{q \nu} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \mu} {e}^{n \nu} {e}^{p \sigma} {e}^{q \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @canonicalise!(%): @rename_dummies!(%): @collect_terms!(%); \end{verbatim}} % Begin TeX comment @collect\_terms: not applicable. % End TeX comment % orig % 1/2 R_{\mu \nu m n} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e e^{m \mu} e^{n \nu} e^{p \rho} - R_{\mu \nu m n} \bar{\epsilon} \Gamma^{p} \psi_{\rho} e e^{m \mu} e^{n \rho} e^{p \nu} + 1/8 R_{\mu \nu m n} \bar{\epsilon} \Gamma^{p q r} \Gamma^{m n} \psi_{\rho} e e^{p \mu} e^{q \nu} e^{r \rho} - T^{\mu}_{\mu \nu} \bar{\epsilon} \Gamma^{m n p} \psi_{\rho \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} - T^{\mu}_{\nu \rho} \bar{\epsilon} \Gamma^{m n p} \psi_{\mu \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} - 1/8 R_{\mu \nu m n} \bar{\psi_{\rho}} \Gamma^{p q r} \Gamma^{m n} \epsilon e e^{p \mu} e^{q \nu} e^{r \rho} - 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \rho} e^{q \sigma} + 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} e^{q \mu} - 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \rho} e^{p \sigma} e^{q \nu} + 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \sigma} e^{q \rho} % end_orig \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= \frac{1}{2}\, {R}_{\mu \nu m n} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\rho} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} - {R}_{\mu \nu m n} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\rho} e {e}^{m \mu} {e}^{n \rho} {e}^{p \nu} + \frac{1}{8}\, {R}_{\mu \nu m n} \bar{\epsilon} {\Gamma}^{p q r} {\Gamma}^{m n} {\psi}_{\rho} e {e}^{p \mu} {e}^{q \nu} {e}^{r \rho} - {T}^{\mu}\,_{\mu \nu} \bar{\epsilon} {\Gamma}^{m n p} {\psi}_{\rho \sigma} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} - {T}^{\mu}\,_{\nu \rho} \bar{\epsilon} {\Gamma}^{m n p} {\psi}_{\mu \sigma} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} - \frac{1}{8}\, {R}_{\mu \nu m n} \bar{{\psi}_{\rho}} {\Gamma}^{p q r} {\Gamma}^{m n} \epsilon e {e}^{p \mu} {e}^{q \nu} {e}^{r \rho} - \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} {e}^{q \sigma} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} {e}^{q \mu} - \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \mu} {e}^{n \rho} {e}^{p \sigma} {e}^{q \nu} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \mu} {e}^{n \nu} {e}^{p \sigma} {e}^{q \rho}; \end{dmath*} % Begin TeX cell closed Let us focus on the two terms with Riemann tensors which were obtained from the gravitino variation. We select them, and then simplify the product of gamma matrices, % End TeX cell {\color[named]{Blue}\begin{verbatim} vpsi:=@take_match[@(L)]( \Gamma^{m n p}\Gamma^{r s} A?? ); \end{verbatim}} % orig % 1/8 R_{\mu \nu m n} \bar{\epsilon} \Gamma^{p q r} \Gamma^{m n} \psi_{\rho} e e^{p \mu} e^{q \nu} e^{r \rho} - 1/8 R_{\mu \nu m n} \bar{\psi_{\rho}} \Gamma^{p q r} \Gamma^{m n} \epsilon e e^{p \mu} e^{q \nu} e^{r \rho} % end_orig \begin{dmath*}[compact, spread=2pt] vpsi\specialcolon{}= \frac{1}{8}\, {R}_{\mu \nu m n} \bar{\epsilon} {\Gamma}^{p q r} {\Gamma}^{m n} {\psi}_{\rho} e {e}^{p \mu} {e}^{q \nu} {e}^{r \rho} - \frac{1}{8}\, {R}_{\mu \nu m n} \bar{{\psi}_{\rho}} {\Gamma}^{p q r} {\Gamma}^{m n} \epsilon e {e}^{p \mu} {e}^{q \nu} {e}^{r \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(vpsi){expand}: @distribute!(%): @spinorsort!(%): @canonicalise!(%); \end{verbatim}} % orig % R_{\mu \nu}^{p q} \bar{\epsilon} \Gamma^{r} \psi_{\rho} e e^{p \mu} e^{q \rho} e^{r \nu} - 1/2 R_{\mu \nu}^{p q} \bar{\epsilon} \Gamma^{r} \psi_{\rho} e e^{p \mu} e^{q \nu} e^{r \rho} % end_orig \begin{dmath*}[compact, spread=2pt] vpsi\specialcolon{}= {R}_{\mu \nu}\,^{p q} \bar{\epsilon} {\Gamma}^{r} {\psi}_{\rho} e {e}^{p \mu} {e}^{q \rho} {e}^{r \nu} - \frac{1}{2}\, {R}_{\mu \nu}\,^{p q} \bar{\epsilon} {\Gamma}^{r} {\psi}_{\rho} e {e}^{p \mu} {e}^{q \nu} {e}^{r \rho}; \end{dmath*} % Begin TeX cell closed That looks nice, we can now plug these terms back into the action where they came from. We then end up with only four-fermi terms, % End TeX cell {\color[named]{Blue}\begin{verbatim} @replace_match!(L)( \Gamma^{m n p}\Gamma^{r s} A?? -> @(vpsi) ): @rename_dummies!(%): @collect_terms!(%); \end{verbatim}} % Begin TeX comment @collect\_terms: not applicable. % End TeX comment % orig % - T^{\mu}_{\mu \nu} \bar{\epsilon} \Gamma^{m n p} \psi_{\rho \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} - T^{\mu}_{\nu \rho} \bar{\epsilon} \Gamma^{m n p} \psi_{\mu \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} - 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \rho} e^{q \sigma} + 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} e^{q \mu} - 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \rho} e^{p \sigma} e^{q \nu} + 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \sigma} e^{q \rho} % end_orig \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= - {T}^{\mu}\,_{\mu \nu} \bar{\epsilon} {\Gamma}^{m n p} {\psi}_{\rho \sigma} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} - {T}^{\mu}\,_{\nu \rho} \bar{\epsilon} {\Gamma}^{m n p} {\psi}_{\mu \sigma} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} - \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} {e}^{q \sigma} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} {e}^{q \mu} - \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \mu} {e}^{n \rho} {e}^{p \sigma} {e}^{q \nu} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \mu} {e}^{n \nu} {e}^{p \sigma} {e}^{q \rho}; \end{dmath*} % Begin TeX cell closed The Riemann tensor terms have cancelled completely. Inserting the torsion now leaves us with % End TeX cell {\color[named]{Blue}\begin{verbatim} @substitute!(%)( T^{\mu}_{\nu\rho} -> -1/4 \bar{\psi_{\nu}} \Gamma^{m} \psi_{\rho} e^{m\mu} ): @canonicalise!(%): @rename_dummies!(%); \end{verbatim}} % orig % 1/4 \bar{\psi_{\mu}} \Gamma^{m} \psi_{\nu} \bar{\epsilon} \Gamma^{n p q} \psi_{\rho \sigma} e e^{m \mu} e^{n \nu} e^{p \rho} e^{q \sigma} + 1/4 \bar{\psi_{\mu}} \Gamma^{m} \psi_{\nu} \bar{\epsilon} \Gamma^{n p q} \psi_{\rho \sigma} e e^{m \rho} e^{n \mu} e^{p \nu} e^{q \sigma} - 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \rho} e^{q \sigma} + 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} e^{q \mu} - 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \rho} e^{p \sigma} e^{q \nu} + 1/2 \bar{\psi_{\mu}} \Gamma^{m n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{m \mu} e^{n \nu} e^{p \sigma} e^{q \rho} % end_orig \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{m} {\psi}_{\nu} \bar{\epsilon} {\Gamma}^{n p q} {\psi}_{\rho \sigma} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} {e}^{q \sigma} + \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{m} {\psi}_{\nu} \bar{\epsilon} {\Gamma}^{n p q} {\psi}_{\rho \sigma} e {e}^{m \rho} {e}^{n \mu} {e}^{p \nu} {e}^{q \sigma} - \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \mu} {e}^{n \nu} {e}^{p \rho} {e}^{q \sigma} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} {e}^{q \mu} - \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \mu} {e}^{n \rho} {e}^{p \sigma} {e}^{q \nu} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{m n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{m \mu} {e}^{n \nu} {e}^{p \sigma} {e}^{q \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @eliminate_vielbein!(%){\Gamma^{m n p}, \Gamma^{m}}; \end{verbatim}} % orig % 1/4 \bar{\psi_{\mu}} \Gamma^{\mu} \psi_{\nu} \bar{\epsilon} \Gamma^{n p q} \psi_{\rho \sigma} e e^{n \nu} e^{p \rho} e^{q \sigma} + 1/4 \bar{\psi_{\mu}} \Gamma^{\rho} \psi_{\nu} \bar{\epsilon} \Gamma^{n p q} \psi_{\rho \sigma} e e^{n \mu} e^{p \nu} e^{q \sigma} - 1/2 \bar{\psi_{\mu}} \Gamma^{\mu n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{n \nu} e^{p \rho} e^{q \sigma} + 1/2 \bar{\psi_{\mu}} \Gamma^{\nu n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{n \rho} e^{p \sigma} e^{q \mu} - 1/2 \bar{\psi_{\mu}} \Gamma^{\mu n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{n \rho} e^{p \sigma} e^{q \nu} + 1/2 \bar{\psi_{\mu}} \Gamma^{\mu n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{n \nu} e^{p \sigma} e^{q \rho} % end_orig \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu} {\psi}_{\nu} \bar{\epsilon} {\Gamma}^{n p q} {\psi}_{\rho \sigma} e {e}^{n \nu} {e}^{p \rho} {e}^{q \sigma} + \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\rho} {\psi}_{\nu} \bar{\epsilon} {\Gamma}^{n p q} {\psi}_{\rho \sigma} e {e}^{n \mu} {e}^{p \nu} {e}^{q \sigma} - \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{n \nu} {e}^{p \rho} {e}^{q \sigma} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{n \rho} {e}^{p \sigma} {e}^{q \mu} - \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{n \rho} {e}^{p \sigma} {e}^{q \nu} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{n \nu} {e}^{p \sigma} {e}^{q \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @canonicalise!(%); \end{verbatim}} % orig % 1/4 \bar{\psi_{\mu}} \Gamma^{\mu} \psi_{\nu} \bar{\epsilon} \Gamma^{n p q} \psi_{\rho \sigma} e e^{n \nu} e^{p \rho} e^{q \sigma} + 1/4 \bar{\psi_{\mu}} \Gamma^{\nu} \psi_{\rho} \bar{\epsilon} \Gamma^{n p q} \psi_{\nu \sigma} e e^{n \mu} e^{p \rho} e^{q \sigma} - 1/2 \bar{\psi_{\mu}} \Gamma^{\mu n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{n \nu} e^{p \rho} e^{q \sigma} + 1/2 \bar{\psi_{\mu}} \Gamma^{\nu n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{n \rho} e^{p \sigma} e^{q \mu} - 1/2 \bar{\psi_{\mu}} \Gamma^{\mu n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{n \rho} e^{p \sigma} e^{q \nu} + 1/2 \bar{\psi_{\mu}} \Gamma^{\mu n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{n \nu} e^{p \sigma} e^{q \rho} % end_orig \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu} {\psi}_{\nu} \bar{\epsilon} {\Gamma}^{n p q} {\psi}_{\rho \sigma} e {e}^{n \nu} {e}^{p \rho} {e}^{q \sigma} + \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu} {\psi}_{\rho} \bar{\epsilon} {\Gamma}^{n p q} {\psi}_{\nu \sigma} e {e}^{n \mu} {e}^{p \rho} {e}^{q \sigma} - \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{n \nu} {e}^{p \rho} {e}^{q \sigma} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{n \rho} {e}^{p \sigma} {e}^{q \mu} - \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{n \rho} {e}^{p \sigma} {e}^{q \nu} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{n \nu} {e}^{p \sigma} {e}^{q \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( \Gamma^{\sigma\nu\rho} D_{\nu}{\psi_{\rho}} ->\Gamma^{\sigma\nu\rho} \psi_{\nu\rho}); \end{verbatim}} % Begin TeX comment @substitute: not applicable. % End TeX comment % orig % 1/4 \bar{\psi_{\mu}} \Gamma^{\mu} \psi_{\nu} \bar{\epsilon} \Gamma^{n p q} \psi_{\rho \sigma} e e^{n \nu} e^{p \rho} e^{q \sigma} + 1/4 \bar{\psi_{\mu}} \Gamma^{\nu} \psi_{\rho} \bar{\epsilon} \Gamma^{n p q} \psi_{\nu \sigma} e e^{n \mu} e^{p \rho} e^{q \sigma} - 1/2 \bar{\psi_{\mu}} \Gamma^{\mu n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{n \nu} e^{p \rho} e^{q \sigma} + 1/2 \bar{\psi_{\mu}} \Gamma^{\nu n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{n \rho} e^{p \sigma} e^{q \mu} - 1/2 \bar{\psi_{\mu}} \Gamma^{\mu n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{n \rho} e^{p \sigma} e^{q \nu} + 1/2 \bar{\psi_{\mu}} \Gamma^{\mu n p} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{q} \psi_{\sigma} e e^{n \nu} e^{p \sigma} e^{q \rho} % end_orig \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu} {\psi}_{\nu} \bar{\epsilon} {\Gamma}^{n p q} {\psi}_{\rho \sigma} e {e}^{n \nu} {e}^{p \rho} {e}^{q \sigma} + \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu} {\psi}_{\rho} \bar{\epsilon} {\Gamma}^{n p q} {\psi}_{\nu \sigma} e {e}^{n \mu} {e}^{p \rho} {e}^{q \sigma} - \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{n \nu} {e}^{p \rho} {e}^{q \sigma} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{n \rho} {e}^{p \sigma} {e}^{q \mu} - \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{n \rho} {e}^{p \sigma} {e}^{q \nu} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu n p} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{q} {\psi}_{\sigma} e {e}^{n \nu} {e}^{p \sigma} {e}^{q \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( D_{\mu}{\psi_{\sigma}} -> 1/2 D_{\mu}{\psi_{\sigma}} + 1/2 D_{\sigma}{\psi_{\mu}} + \psi_{\mu\sigma} ): @distribute!(%); @canonicalise!(%): @rename_dummies!(%): @collect_terms!(%); \end{verbatim}} % orig % 1/4 \bar{\psi_{\mu}} \Gamma^{\mu} \psi_{\nu} \bar{\epsilon} \Gamma^{m n p} \psi_{\rho \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} + 1/4 \bar{\psi_{\mu}} \Gamma^{\nu} \psi_{\rho} \bar{\epsilon} \Gamma^{m n p} \psi_{\nu \sigma} e e^{m \mu} e^{n \rho} e^{p \sigma} - 1/2 \bar{\psi_{\mu}} \Gamma^{\mu m n} \psi_{\nu \rho} \bar{\epsilon} \Gamma^{p} \psi_{\sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} + 1/4 \bar{\psi_{\mu}} \Gamma^{\nu m n} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{p} \psi_{\sigma} e e^{m \rho} e^{n \sigma} e^{p \mu} + 1/4 \bar{\psi_{\mu}} \Gamma^{\nu m n} D_{\rho}{\psi_{\nu}} \bar{\epsilon} \Gamma^{p} \psi_{\sigma} e e^{m \rho} e^{n \sigma} e^{p \mu} + 3/4 \bar{\psi_{\mu}} \Gamma^{\nu m n} \psi_{\nu \rho} \bar{\epsilon} \Gamma^{p} \psi_{\sigma} e e^{m \rho} e^{n \sigma} e^{p \mu} + 1/4 \bar{\psi_{\mu}} \Gamma^{\nu m n} \psi_{\rho \nu} \bar{\epsilon} \Gamma^{p} \psi_{\sigma} e e^{m \rho} e^{n \sigma} e^{p \mu} + \bar{\psi_{\mu}} \Gamma^{\mu m n} \psi_{\nu \rho} \bar{\epsilon} \Gamma^{p} \psi_{\sigma} e e^{m \nu} e^{n \sigma} e^{p \rho} % end_orig \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu} {\psi}_{\nu} \bar{\epsilon} {\Gamma}^{m n p} {\psi}_{\rho \sigma} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} + \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu} {\psi}_{\rho} \bar{\epsilon} {\Gamma}^{m n p} {\psi}_{\nu \sigma} e {e}^{m \mu} {e}^{n \rho} {e}^{p \sigma} - \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu m n} {\psi}_{\nu \rho} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\sigma} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} + \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu m n} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\sigma} e {e}^{m \rho} {e}^{n \sigma} {e}^{p \mu} + \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu m n} {D}_{\rho}{{\psi}_{\nu}} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\sigma} e {e}^{m \rho} {e}^{n \sigma} {e}^{p \mu} + \frac{3}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu m n} {\psi}_{\nu \rho} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\sigma} e {e}^{m \rho} {e}^{n \sigma} {e}^{p \mu} + \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu m n} {\psi}_{\rho \nu} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\sigma} e {e}^{m \rho} {e}^{n \sigma} {e}^{p \mu} + \bar{{\psi}_{\mu}} {\Gamma}^{\mu m n} {\psi}_{\nu \rho} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\sigma} e {e}^{m \nu} {e}^{n \sigma} {e}^{p \rho}; \end{dmath*} % Begin TeX comment @collect\_terms: not applicable. % End TeX comment % orig % 1/4 \bar{\psi_{\mu}} \Gamma^{\mu} \psi_{\nu} \bar{\epsilon} \Gamma^{m n p} \psi_{\rho \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} + 1/4 \bar{\psi_{\mu}} \Gamma^{\nu} \psi_{\rho} \bar{\epsilon} \Gamma^{m n p} \psi_{\nu \sigma} e e^{m \mu} e^{n \rho} e^{p \sigma} - 1/2 \bar{\psi_{\mu}} \Gamma^{\mu m n} \psi_{\nu \rho} \bar{\epsilon} \Gamma^{p} \psi_{\sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} + 1/4 \bar{\psi_{\mu}} \Gamma^{\nu m n} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{p} \psi_{\sigma} e e^{m \rho} e^{n \sigma} e^{p \mu} + 1/4 \bar{\psi_{\mu}} \Gamma^{\nu m n} D_{\rho}{\psi_{\nu}} \bar{\epsilon} \Gamma^{p} \psi_{\sigma} e e^{m \rho} e^{n \sigma} e^{p \mu} + 1/2 \bar{\psi_{\mu}} \Gamma^{\nu m n} \psi_{\nu \rho} \bar{\epsilon} \Gamma^{p} \psi_{\sigma} e e^{m \rho} e^{n \sigma} e^{p \mu} + \bar{\psi_{\mu}} \Gamma^{\mu m n} \psi_{\nu \rho} \bar{\epsilon} \Gamma^{p} \psi_{\sigma} e e^{m \nu} e^{n \sigma} e^{p \rho} % end_orig \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu} {\psi}_{\nu} \bar{\epsilon} {\Gamma}^{m n p} {\psi}_{\rho \sigma} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} + \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu} {\psi}_{\rho} \bar{\epsilon} {\Gamma}^{m n p} {\psi}_{\nu \sigma} e {e}^{m \mu} {e}^{n \rho} {e}^{p \sigma} - \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu m n} {\psi}_{\nu \rho} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\sigma} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} + \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu m n} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\sigma} e {e}^{m \rho} {e}^{n \sigma} {e}^{p \mu} + \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu m n} {D}_{\rho}{{\psi}_{\nu}} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\sigma} e {e}^{m \rho} {e}^{n \sigma} {e}^{p \mu} + \frac{1}{2}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu m n} {\psi}_{\nu \rho} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\sigma} e {e}^{m \rho} {e}^{n \sigma} {e}^{p \mu} + \bar{{\psi}_{\mu}} {\Gamma}^{\mu m n} {\psi}_{\nu \rho} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\sigma} e {e}^{m \nu} {e}^{n \sigma} {e}^{p \rho}; \end{dmath*} % Begin TeX cell closed Now we need to Fierz, indicating the preferred form of the bilinears. We will sort such that the fermion pairs appear as $\psi\psi$ and $\epsilon\psi_{(2)}$. % End TeX cell {\color[named]{Blue}\begin{verbatim} @fierz!(%)( \psi_{\mu}, \psi_{\rho}, \epsilon, \psi_{\sigma\kappa} ); \end{verbatim}} % orig % 1/4 \bar{\psi_{\mu}} \Gamma^{\mu} \psi_{\nu} \bar{\epsilon} \Gamma^{m n p} \psi_{\rho \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} + 1/4 \bar{\psi_{\mu}} \Gamma^{\nu} \psi_{\rho} \bar{\epsilon} \Gamma^{m n p} \psi_{\nu \sigma} e e^{m \mu} e^{n \rho} e^{p \sigma} + 1/8 \bar{\psi_{\mu}} \Gamma^{\mu m n} \Gamma^{p} \psi_{\sigma} \bar{\epsilon} \psi_{\nu \rho} e e^{m \nu} e^{n \rho} e^{p \sigma} + 1/8 \bar{\psi_{\mu}} \Gamma^{\mu m n} \Gamma^{\kappa} \Gamma^{p} \psi_{\sigma} \bar{\epsilon} \Gamma_{\kappa} \psi_{\nu \rho} e e^{m \nu} e^{n \rho} e^{p \sigma} + 1/16 \bar{\psi_{\mu}} \Gamma^{\mu m n} \Gamma^{\kappa \lambda} \Gamma^{p} \psi_{\sigma} \bar{\epsilon} \Gamma_{\lambda \kappa} \psi_{\nu \rho} e e^{m \nu} e^{n \rho} e^{p \sigma} + 1/4 \bar{\psi_{\mu}} \Gamma^{\nu m n} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{p} \psi_{\sigma} e e^{m \rho} e^{n \sigma} e^{p \mu} + 1/4 \bar{\psi_{\mu}} \Gamma^{\nu m n} D_{\rho}{\psi_{\nu}} \bar{\epsilon} \Gamma^{p} \psi_{\sigma} e e^{m \rho} e^{n \sigma} e^{p \mu} - 1/8 \bar{\psi_{\mu}} \Gamma^{\nu m n} \Gamma^{p} \psi_{\sigma} \bar{\epsilon} \psi_{\nu \rho} e e^{m \rho} e^{n \sigma} e^{p \mu} - 1/8 \bar{\psi_{\mu}} \Gamma^{\nu m n} \Gamma^{\kappa} \Gamma^{p} \psi_{\sigma} \bar{\epsilon} \Gamma_{\kappa} \psi_{\nu \rho} e e^{m \rho} e^{n \sigma} e^{p \mu} - 1/16 \bar{\psi_{\mu}} \Gamma^{\nu m n} \Gamma^{\kappa \lambda} \Gamma^{p} \psi_{\sigma} \bar{\epsilon} \Gamma_{\lambda \kappa} \psi_{\nu \rho} e e^{m \rho} e^{n \sigma} e^{p \mu} - 1/4 \bar{\psi_{\mu}} \Gamma^{\mu m n} \Gamma^{p} \psi_{\sigma} \bar{\epsilon} \psi_{\nu \rho} e e^{m \nu} e^{n \sigma} e^{p \rho} - 1/4 \bar{\psi_{\mu}} \Gamma^{\mu m n} \Gamma^{\kappa} \Gamma^{p} \psi_{\sigma} \bar{\epsilon} \Gamma_{\kappa} \psi_{\nu \rho} e e^{m \nu} e^{n \sigma} e^{p \rho} - 1/8 \bar{\psi_{\mu}} \Gamma^{\mu m n} \Gamma^{\kappa \lambda} \Gamma^{p} \psi_{\sigma} \bar{\epsilon} \Gamma_{\lambda \kappa} \psi_{\nu \rho} e e^{m \nu} e^{n \sigma} e^{p \rho} % end_orig \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu} {\psi}_{\nu} \bar{\epsilon} {\Gamma}^{m n p} {\psi}_{\rho \sigma} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} + \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu} {\psi}_{\rho} \bar{\epsilon} {\Gamma}^{m n p} {\psi}_{\nu \sigma} e {e}^{m \mu} {e}^{n \rho} {e}^{p \sigma} + \frac{1}{8}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu m n} {\Gamma}^{p} {\psi}_{\sigma} \bar{\epsilon} {\psi}_{\nu \rho} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} + \frac{1}{8}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu m n} {\Gamma}^{\kappa} {\Gamma}^{p} {\psi}_{\sigma} \bar{\epsilon} {\Gamma}_{\kappa} {\psi}_{\nu \rho} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} + \frac{1}{16}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu m n} {\Gamma}^{\kappa \lambda} {\Gamma}^{p} {\psi}_{\sigma} \bar{\epsilon} {\Gamma}_{\lambda \kappa} {\psi}_{\nu \rho} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} + \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu m n} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\sigma} e {e}^{m \rho} {e}^{n \sigma} {e}^{p \mu} + \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu m n} {D}_{\rho}{{\psi}_{\nu}} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\sigma} e {e}^{m \rho} {e}^{n \sigma} {e}^{p \mu} - \frac{1}{8}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu m n} {\Gamma}^{p} {\psi}_{\sigma} \bar{\epsilon} {\psi}_{\nu \rho} e {e}^{m \rho} {e}^{n \sigma} {e}^{p \mu} - \frac{1}{8}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu m n} {\Gamma}^{\kappa} {\Gamma}^{p} {\psi}_{\sigma} \bar{\epsilon} {\Gamma}_{\kappa} {\psi}_{\nu \rho} e {e}^{m \rho} {e}^{n \sigma} {e}^{p \mu} - \frac{1}{16}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu m n} {\Gamma}^{\kappa \lambda} {\Gamma}^{p} {\psi}_{\sigma} \bar{\epsilon} {\Gamma}_{\lambda \kappa} {\psi}_{\nu \rho} e {e}^{m \rho} {e}^{n \sigma} {e}^{p \mu} - \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu m n} {\Gamma}^{p} {\psi}_{\sigma} \bar{\epsilon} {\psi}_{\nu \rho} e {e}^{m \nu} {e}^{n \sigma} {e}^{p \rho} - \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu m n} {\Gamma}^{\kappa} {\Gamma}^{p} {\psi}_{\sigma} \bar{\epsilon} {\Gamma}_{\kappa} {\psi}_{\nu \rho} e {e}^{m \nu} {e}^{n \sigma} {e}^{p \rho} - \frac{1}{8}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu m n} {\Gamma}^{\kappa \lambda} {\Gamma}^{p} {\psi}_{\sigma} \bar{\epsilon} {\Gamma}_{\lambda \kappa} {\psi}_{\nu \rho} e {e}^{m \nu} {e}^{n \sigma} {e}^{p \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}: @distribute!(%): @prodsort!(%): @join!(%){expand}: @distribute!(%): @prodsort!(%): @canonicalise!(%): @rename_dummies!(%): @collect_terms!(%); \end{verbatim}} {\color[named]{Red}% ERROR: The gamma matrix property does not contain metric information.% } % error % Begin TeX comment @distribute: not applicable. % End TeX comment % Begin TeX comment @prodsort: not applicable. % End TeX comment {\color[named]{Red}% ERROR: The gamma matrix property does not contain metric information.% } % error % Begin TeX comment @distribute: not applicable. % End TeX comment % Begin TeX comment @prodsort: not applicable. % End TeX comment % Begin TeX comment @collect\_terms: not applicable. % End TeX comment % orig % 1/4 \bar{\psi_{\mu}} \Gamma^{\mu} \psi_{\nu} \bar{\epsilon} \Gamma^{m n p} \psi_{\rho \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} + 1/4 \bar{\psi_{\mu}} \Gamma^{\nu} \psi_{\rho} \bar{\epsilon} \Gamma^{m n p} \psi_{\nu \sigma} e e^{m \mu} e^{n \rho} e^{p \sigma} + 1/8 \bar{\psi_{\mu}} \Gamma^{\mu m n} \Gamma^{p} \psi_{\nu} \bar{\epsilon} \psi_{\rho \sigma} e e^{m \rho} e^{n \sigma} e^{p \nu} + 1/8 \bar{\psi_{\mu}} \Gamma^{\mu m n} \Gamma^{\nu} \Gamma^{p} \psi_{\rho} \bar{\epsilon} \Gamma_{\nu} \psi_{\sigma \kappa} e e^{m \sigma} e^{n \kappa} e^{p \rho} - 1/16 \bar{\psi_{\mu}} \Gamma^{\mu m n} \Gamma^{\nu \rho} \Gamma^{p} \psi_{\sigma} \bar{\epsilon} \Gamma_{\nu \rho} \psi_{\kappa \lambda} e e^{m \kappa} e^{n \lambda} e^{p \sigma} + 1/4 \bar{\psi_{\mu}} \Gamma^{\nu m n} D_{\nu}{\psi_{\rho}} \bar{\epsilon} \Gamma^{p} \psi_{\sigma} e e^{m \rho} e^{n \sigma} e^{p \mu} + 1/4 \bar{\psi_{\mu}} \Gamma^{\nu m n} D_{\rho}{\psi_{\nu}} \bar{\epsilon} \Gamma^{p} \psi_{\sigma} e e^{m \rho} e^{n \sigma} e^{p \mu} + 1/8 \bar{\psi_{\mu}} \Gamma^{\nu m n} \Gamma^{p} \psi_{\rho} \bar{\epsilon} \psi_{\nu \sigma} e e^{m \rho} e^{n \sigma} e^{p \mu} + 1/8 \bar{\psi_{\mu}} \Gamma^{\nu m n} \Gamma^{\rho} \Gamma^{p} \psi_{\sigma} \bar{\epsilon} \Gamma_{\rho} \psi_{\nu \kappa} e e^{m \sigma} e^{n \kappa} e^{p \mu} - 1/16 \bar{\psi_{\mu}} \Gamma^{\nu m n} \Gamma^{\rho \sigma} \Gamma^{p} \psi_{\kappa} \bar{\epsilon} \Gamma_{\rho \sigma} \psi_{\nu \lambda} e e^{m \kappa} e^{n \lambda} e^{p \mu} + 1/4 \bar{\psi_{\mu}} \Gamma^{\mu m n} \Gamma^{p} \psi_{\nu} \bar{\epsilon} \psi_{\rho \sigma} e e^{m \nu} e^{n \rho} e^{p \sigma} + 1/4 \bar{\psi_{\mu}} \Gamma^{\mu m n} \Gamma^{\nu} \Gamma^{p} \psi_{\rho} \bar{\epsilon} \Gamma_{\nu} \psi_{\sigma \kappa} e e^{m \rho} e^{n \sigma} e^{p \kappa} - 1/8 \bar{\psi_{\mu}} \Gamma^{\mu m n} \Gamma^{\nu \rho} \Gamma^{p} \psi_{\sigma} \bar{\epsilon} \Gamma_{\nu \rho} \psi_{\kappa \lambda} e e^{m \sigma} e^{n \kappa} e^{p \lambda} % end_orig \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu} {\psi}_{\nu} \bar{\epsilon} {\Gamma}^{m n p} {\psi}_{\rho \sigma} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} + \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu} {\psi}_{\rho} \bar{\epsilon} {\Gamma}^{m n p} {\psi}_{\nu \sigma} e {e}^{m \mu} {e}^{n \rho} {e}^{p \sigma} + \frac{1}{8}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu m n} {\Gamma}^{p} {\psi}_{\nu} \bar{\epsilon} {\psi}_{\rho \sigma} e {e}^{m \rho} {e}^{n \sigma} {e}^{p \nu} + \frac{1}{8}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu m n} {\Gamma}^{\nu} {\Gamma}^{p} {\psi}_{\rho} \bar{\epsilon} {\Gamma}_{\nu} {\psi}_{\sigma \kappa} e {e}^{m \sigma} {e}^{n \kappa} {e}^{p \rho} - \frac{1}{16}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu m n} {\Gamma}^{\nu \rho} {\Gamma}^{p} {\psi}_{\sigma} \bar{\epsilon} {\Gamma}_{\nu \rho} {\psi}_{\kappa \lambda} e {e}^{m \kappa} {e}^{n \lambda} {e}^{p \sigma} + \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu m n} {D}_{\nu}{{\psi}_{\rho}} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\sigma} e {e}^{m \rho} {e}^{n \sigma} {e}^{p \mu} + \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu m n} {D}_{\rho}{{\psi}_{\nu}} \bar{\epsilon} {\Gamma}^{p} {\psi}_{\sigma} e {e}^{m \rho} {e}^{n \sigma} {e}^{p \mu} + \frac{1}{8}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu m n} {\Gamma}^{p} {\psi}_{\rho} \bar{\epsilon} {\psi}_{\nu \sigma} e {e}^{m \rho} {e}^{n \sigma} {e}^{p \mu} + \frac{1}{8}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu m n} {\Gamma}^{\rho} {\Gamma}^{p} {\psi}_{\sigma} \bar{\epsilon} {\Gamma}_{\rho} {\psi}_{\nu \kappa} e {e}^{m \sigma} {e}^{n \kappa} {e}^{p \mu} - \frac{1}{16}\, \bar{{\psi}_{\mu}} {\Gamma}^{\nu m n} {\Gamma}^{\rho \sigma} {\Gamma}^{p} {\psi}_{\kappa} \bar{\epsilon} {\Gamma}_{\rho \sigma} {\psi}_{\nu \lambda} e {e}^{m \kappa} {e}^{n \lambda} {e}^{p \mu} + \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu m n} {\Gamma}^{p} {\psi}_{\nu} \bar{\epsilon} {\psi}_{\rho \sigma} e {e}^{m \nu} {e}^{n \rho} {e}^{p \sigma} + \frac{1}{4}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu m n} {\Gamma}^{\nu} {\Gamma}^{p} {\psi}_{\rho} \bar{\epsilon} {\Gamma}_{\nu} {\psi}_{\sigma \kappa} e {e}^{m \rho} {e}^{n \sigma} {e}^{p \kappa} - \frac{1}{8}\, \bar{{\psi}_{\mu}} {\Gamma}^{\mu m n} {\Gamma}^{\nu \rho} {\Gamma}^{p} {\psi}_{\sigma} \bar{\epsilon} {\Gamma}_{\nu \rho} {\psi}_{\kappa \lambda} e {e}^{m \sigma} {e}^{n \kappa} {e}^{p \lambda}; \end{dmath*} % Begin TeX cell closed Finally, eliminate the metric and collect terms. % End TeX cell {\color[named]{Blue}\begin{verbatim} @eliminate_metric!(%)( \Gamma_{\sigma\kappa\lambda}, \Gamma_{\sigma\kappa\lambda\rho} ): @rename_dummies!(%): @collect_terms!(%); \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= \frac{3}{4}\, \bar{\psi_{\mu}} \Gamma^{\mu} \psi_{\nu} \bar{\epsilon} \Gamma^{\nu \rho \sigma} \psi_{\rho \sigma} e + \frac{3}{4}\, \bar{\psi_{\mu}} \Gamma^{\nu} \psi_{\rho} \bar{\epsilon} \Gamma^{\mu \rho \sigma} \psi_{\nu \sigma} e - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{\mu \nu} \psi_{\rho} \bar{\epsilon} \Gamma_{\nu}\,^{\rho \sigma \kappa} \psi_{\sigma \kappa} e + \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma^{\nu \rho} \psi_{\sigma} \bar{\epsilon} \Gamma_{\nu}\,^{\mu \sigma \kappa} \psi_{\rho \kappa} e; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @canonicalise!(%); \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] L\specialcolon{}= \frac{3}{4}\, \bar{\psi_{\mu}} \Gamma^{\mu} \psi_{\nu} \bar{\epsilon} \Gamma^{\nu \rho \sigma} \psi_{\rho \sigma} e + \frac{3}{4}\, \bar{\psi_{\mu}} \Gamma^{\nu} \psi_{\rho} \bar{\epsilon} \Gamma^{\mu \rho \sigma} \psi_{\nu \sigma} e - \frac{1}{2}\, \bar{\psi_{\kappa}} \Gamma^{\kappa \mu} \psi_{\nu} \bar{\epsilon} \Gamma_{\mu}\,^{\nu \rho \sigma} \psi_{\rho \sigma} e - \frac{1}{2}\, \bar{\psi_{\kappa}} \Gamma^{\mu \nu} \psi_{\rho} \bar{\epsilon} \Gamma_{\kappa}\,^{\mu \rho \sigma} \psi_{\nu \sigma} e; \end{dmath*} % Begin TeX cell closed Since this does not quite vanish yet, we try to first verify the van Nieuwenhuizen result. See page 213. % End TeX cell {\color[named]{Blue}\begin{verbatim} tst:= -1/4 \epsilon^{\mu\nu\rho\sigma} \epsilon_{m n p q} \bar{\psi_{\mu}} \Gamma_{m n p q} \Gamma_{r} \psi_{\rho\sigma} \bar{\epsilon}\Gamma_{r}\psi_{\nu}; \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] tst\specialcolon{}= (\frac{-1}{4})\, \bar{\psi_{\mu}} \Gamma_{m n p q} \Gamma_{r} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\rho \sigma} \bar{\epsilon} \Gamma_{r} \psi_{\nu}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}; \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] tst\specialcolon{}= (\frac{-1}{4})\, \bar{\psi_{\mu}} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} (\Gamma_{m n p} \delta_{q r} - \Gamma_{m n q} \delta_{p r} + \Gamma_{m p q} \delta_{n r} - \Gamma_{n p q} \delta_{m r}) \psi_{\rho \sigma} \bar{\epsilon} \Gamma_{r} \psi_{\nu}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @distribute!(%); \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] tst\specialcolon{}= - \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma_{m n p} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p r} \psi_{\rho \sigma} \bar{\epsilon} \Gamma_{r} \psi_{\nu} + \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma_{m n q} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n r q} \psi_{\rho \sigma} \bar{\epsilon} \Gamma_{r} \psi_{\nu} - \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma_{m p q} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m r p q} \psi_{\rho \sigma} \bar{\epsilon} \Gamma_{r} \psi_{\nu} + \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma_{n p q} \epsilon^{\mu \nu \rho \sigma} \epsilon_{r n p q} \psi_{\rho \sigma} \bar{\epsilon} \Gamma_{r} \psi_{\nu}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @canonicalise!(%): @rename_dummies!(%); \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] tst\specialcolon{}= (-1)\, \bar{\psi_{\mu}} \Gamma_{m n p} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\nu \rho} \bar{\epsilon} \Gamma_{q} \psi_{\sigma}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @fierz!(%){ \psi_{\mu}, \psi_{\nu}, \epsilon, \psi_{\mu\nu} }; \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] tst\specialcolon{}= \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma_{m n p} \Gamma_{q} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\sigma} \bar{\epsilon} \psi_{\nu \rho} + \frac{1}{4}\, \bar{\psi_{\mu}} \Gamma_{m n p} \Gamma_{r} \Gamma_{q} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\sigma} \bar{\epsilon} \Gamma_{r} \psi_{\nu \rho} + \frac{1}{8}\, \bar{\psi_{\mu}} \Gamma_{m n p} \Gamma_{r s} \Gamma_{q} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\sigma} \bar{\epsilon} \Gamma_{s r} \psi_{\nu \rho} + \frac{1}{24}\, \bar{\psi_{\mu}} \Gamma_{m n p} \Gamma_{r s t} \Gamma_{q} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\sigma} \bar{\epsilon} \Gamma_{t s r} \psi_{\nu \rho} + \frac{1}{96}\, \bar{\psi_{\mu}} \Gamma_{m n p} \Gamma_{r s t u} \Gamma_{q} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\sigma} \bar{\epsilon} \Gamma_{u t s r} \psi_{\nu \rho}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}: @distribute!(%): @join!(%){expand}: @distribute!(%): @canonicalise!(%): @rename_dummies!(%); \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] tst\specialcolon{}= \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma_{m} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\nu} \bar{\epsilon} \Gamma_{n p q} \psi_{\rho \sigma} - \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma_{m n} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m p q r} \psi_{\nu} \bar{\epsilon} \Gamma_{n p q r} \psi_{\rho \sigma}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} torep:=\Gamma_{m n} \epsilon_{m p q r}; \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] torep\specialcolon{}= \Gamma_{m n} \epsilon_{m p q r}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @decompose_product!(%): @canonicalise!(%); \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] torep\specialcolon{}= \frac{3}{4}\, \Gamma_{n m} \epsilon_{p q r m} + \frac{1}{4}\, \Gamma_{p m} \epsilon_{n q r m} - \frac{1}{4}\, \Gamma_{q m} \epsilon_{n p r m} + \frac{1}{4}\, \Gamma_{r m} \epsilon_{n p q m}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @substitute!(tst)( \Gamma_{m n} \epsilon_{m p q r} -> @(torep) ): @distribute!(%): @canonicalise!(%): @collect_terms!(%); \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] tst\specialcolon{}= \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma_{m} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\nu} \bar{\epsilon} \Gamma_{n p q} \psi_{\rho \sigma}; \end{dmath*} % Begin TeX cell closed This is supposed to be proportional to % End TeX cell {\color[named]{Blue}\begin{verbatim} tst2:= 1/8 \epsilon^{\mu\nu\rho\sigma} \epsilon_{m n p q} \bar{\psi_{\mu}} \Gamma_{r} \psi_{\nu} \bar{\epsilon} \Gamma_{r}\Gamma_{m n p q}\psi_{\rho\sigma}; \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] tst2\specialcolon{}= \frac{1}{8}\, \bar{\psi_{\mu}} \Gamma_{r} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\nu} \bar{\epsilon} \Gamma_{r} \Gamma_{m n p q} \psi_{\rho \sigma}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}: @distribute!(%): @canonicalise!(%): @rename_dummies!(%); \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] tst2\specialcolon{}= \frac{1}{2}\, \bar{\psi_{\mu}} \Gamma_{m} \epsilon^{\mu \nu \rho \sigma} \epsilon_{m n p q} \psi_{\nu} \bar{\epsilon} \Gamma_{n p q} \psi_{\rho \sigma}; \end{dmath*} \begin{verbatim} @join: not applicable. @distribute: not applicable. \end{verbatim} {\color[named]{Blue}\begin{verbatim} @(tst)-@(tst2); \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] 18\specialcolon{}= 0; \end{dmath*} % Begin TeX cell closed Some random tests inspired by what happened above. % End TeX cell {\color[named]{Blue}\begin{verbatim} \epsilon_{m n p q} \Gamma_{m n p q} \Gamma_{r} \Gamma_{s t} \Gamma_{r}; \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= \Gamma_{m n p q} \Gamma_{r} \Gamma_{s t} \Gamma_{r} \epsilon_{m n p q}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}; \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= (\Gamma_{m n p} \delta_{q r} - \Gamma_{m n q} \delta_{p r} + \Gamma_{m p q} \delta_{n r} - \Gamma_{n p q} \delta_{m r}) \Gamma_{s t} \Gamma_{r} \epsilon_{m n p q}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @distribute!(%); \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= \Gamma_{m n p} \Gamma_{s t} \Gamma_{q} \epsilon_{m n p q} - \Gamma_{m n q} \Gamma_{s t} \Gamma_{p} \epsilon_{m n p q} + \Gamma_{m p q} \Gamma_{s t} \Gamma_{n} \epsilon_{m n p q} - \Gamma_{n p q} \Gamma_{s t} \Gamma_{m} \epsilon_{m n p q}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}; \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= (\Gamma_{m n t} \delta_{p s} - \Gamma_{m n s} \delta_{p t} - \Gamma_{m p t} \delta_{n s} + \Gamma_{m p s} \delta_{n t} + \Gamma_{n p t} \delta_{m s} - \Gamma_{n p s} \delta_{m t} + \Gamma_{m} \delta_{n t} \delta_{p s} - \Gamma_{m} \delta_{n s} \delta_{p t} - \Gamma_{p} \delta_{m s} \delta_{n t} + \Gamma_{p} \delta_{m t} \delta_{n s} + \Gamma_{n} \delta_{m s} \delta_{p t} - \Gamma_{n} \delta_{m t} \delta_{p s}) \Gamma_{q} \epsilon_{m n p q} - (\Gamma_{m n t} \delta_{q s} - \Gamma_{m n s} \delta_{q t} - \Gamma_{m q t} \delta_{n s} + \Gamma_{m q s} \delta_{n t} + \Gamma_{n q t} \delta_{m s} - \Gamma_{n q s} \delta_{m t} + \Gamma_{m} \delta_{n t} \delta_{q s} - \Gamma_{m} \delta_{n s} \delta_{q t} - \Gamma_{q} \delta_{m s} \delta_{n t} + \Gamma_{q} \delta_{m t} \delta_{n s} + \Gamma_{n} \delta_{m s} \delta_{q t} - \Gamma_{n} \delta_{m t} \delta_{q s}) \Gamma_{p} \epsilon_{m n p q} + (\Gamma_{m p t} \delta_{q s} - \Gamma_{m p s} \delta_{q t} - \Gamma_{m q t} \delta_{p s} + \Gamma_{m q s} \delta_{p t} + \Gamma_{p q t} \delta_{m s} - \Gamma_{p q s} \delta_{m t} + \Gamma_{m} \delta_{p t} \delta_{q s} - \Gamma_{m} \delta_{p s} \delta_{q t} - \Gamma_{q} \delta_{m s} \delta_{p t} + \Gamma_{q} \delta_{m t} \delta_{p s} + \Gamma_{p} \delta_{m s} \delta_{q t} - \Gamma_{p} \delta_{m t} \delta_{q s}) \Gamma_{n} \epsilon_{m n p q} - (\Gamma_{n p t} \delta_{q s} - \Gamma_{n p s} \delta_{q t} - \Gamma_{n q t} \delta_{p s} + \Gamma_{n q s} \delta_{p t} + \Gamma_{p q t} \delta_{n s} - \Gamma_{p q s} \delta_{n t} + \Gamma_{n} \delta_{p t} \delta_{q s} - \Gamma_{n} \delta_{p s} \delta_{q t} - \Gamma_{q} \delta_{n s} \delta_{p t} + \Gamma_{q} \delta_{n t} \delta_{p s} + \Gamma_{p} \delta_{n s} \delta_{q t} - \Gamma_{p} \delta_{n t} \delta_{q s}) \Gamma_{m} \epsilon_{m n p q}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @distribute!(%); \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= \Gamma_{m n t} \Gamma_{q} \epsilon_{m n s q} - \Gamma_{m n s} \Gamma_{q} \epsilon_{m n t q} - \Gamma_{m p t} \Gamma_{q} \epsilon_{m s p q} + \Gamma_{m p s} \Gamma_{q} \epsilon_{m t p q} + \Gamma_{n p t} \Gamma_{q} \epsilon_{s n p q} - \Gamma_{n p s} \Gamma_{q} \epsilon_{t n p q} + \Gamma_{m} \Gamma_{q} \epsilon_{m t s q} - \Gamma_{m} \Gamma_{q} \epsilon_{m s t q} - \Gamma_{p} \Gamma_{q} \epsilon_{s t p q} + \Gamma_{p} \Gamma_{q} \epsilon_{t s p q} + \Gamma_{n} \Gamma_{q} \epsilon_{s n t q} - \Gamma_{n} \Gamma_{q} \epsilon_{t n s q} - \Gamma_{m n t} \Gamma_{p} \epsilon_{m n p s} + \Gamma_{m n s} \Gamma_{p} \epsilon_{m n p t} + \Gamma_{m q t} \Gamma_{p} \epsilon_{m s p q} - \Gamma_{m q s} \Gamma_{p} \epsilon_{m t p q} - \Gamma_{n q t} \Gamma_{p} \epsilon_{s n p q} + \Gamma_{n q s} \Gamma_{p} \epsilon_{t n p q} - \Gamma_{m} \Gamma_{p} \epsilon_{m t p s} + \Gamma_{m} \Gamma_{p} \epsilon_{m s p t} + \Gamma_{q} \Gamma_{p} \epsilon_{s t p q} - \Gamma_{q} \Gamma_{p} \epsilon_{t s p q} - \Gamma_{n} \Gamma_{p} \epsilon_{s n p t} + \Gamma_{n} \Gamma_{p} \epsilon_{t n p s} + \Gamma_{m p t} \Gamma_{n} \epsilon_{m n p s} - \Gamma_{m p s} \Gamma_{n} \epsilon_{m n p t} - \Gamma_{m q t} \Gamma_{n} \epsilon_{m n s q} + \Gamma_{m q s} \Gamma_{n} \epsilon_{m n t q} + \Gamma_{p q t} \Gamma_{n} \epsilon_{s n p q} - \Gamma_{p q s} \Gamma_{n} \epsilon_{t n p q} + \Gamma_{m} \Gamma_{n} \epsilon_{m n t s} - \Gamma_{m} \Gamma_{n} \epsilon_{m n s t} - \Gamma_{q} \Gamma_{n} \epsilon_{s n t q} + \Gamma_{q} \Gamma_{n} \epsilon_{t n s q} + \Gamma_{p} \Gamma_{n} \epsilon_{s n p t} - \Gamma_{p} \Gamma_{n} \epsilon_{t n p s} - \Gamma_{n p t} \Gamma_{m} \epsilon_{m n p s} + \Gamma_{n p s} \Gamma_{m} \epsilon_{m n p t} + \Gamma_{n q t} \Gamma_{m} \epsilon_{m n s q} - \Gamma_{n q s} \Gamma_{m} \epsilon_{m n t q} - \Gamma_{p q t} \Gamma_{m} \epsilon_{m s p q} + \Gamma_{p q s} \Gamma_{m} \epsilon_{m t p q} - \Gamma_{n} \Gamma_{m} \epsilon_{m n t s} + \Gamma_{n} \Gamma_{m} \epsilon_{m n s t} + \Gamma_{q} \Gamma_{m} \epsilon_{m s t q} - \Gamma_{q} \Gamma_{m} \epsilon_{m t s q} - \Gamma_{p} \Gamma_{m} \epsilon_{m s p t} + \Gamma_{p} \Gamma_{m} \epsilon_{m t p s}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}; \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= \epsilon_{m n s q} (\Gamma_{m n t q} + \Gamma_{m n} \delta_{q t} - \Gamma_{m t} \delta_{n q} + \Gamma_{n t} \delta_{m q}) - \epsilon_{m n t q} (\Gamma_{m n s q} + \Gamma_{m n} \delta_{q s} - \Gamma_{m s} \delta_{n q} + \Gamma_{n s} \delta_{m q}) - \epsilon_{m s p q} (\Gamma_{m p t q} + \Gamma_{m p} \delta_{q t} - \Gamma_{m t} \delta_{p q} + \Gamma_{p t} \delta_{m q}) + \epsilon_{m t p q} (\Gamma_{m p s q} + \Gamma_{m p} \delta_{q s} - \Gamma_{m s} \delta_{p q} + \Gamma_{p s} \delta_{m q}) + \epsilon_{s n p q} (\Gamma_{n p t q} + \Gamma_{n p} \delta_{q t} - \Gamma_{n t} \delta_{p q} + \Gamma_{p t} \delta_{n q}) - \epsilon_{t n p q} (\Gamma_{n p s q} + \Gamma_{n p} \delta_{q s} - \Gamma_{n s} \delta_{p q} + \Gamma_{p s} \delta_{n q}) + \epsilon_{m t s q} (\Gamma_{m q} + \delta_{m q}) - \epsilon_{m s t q} (\Gamma_{m q} + \delta_{m q}) - \epsilon_{s t p q} (\Gamma_{p q} + \delta_{p q}) + \epsilon_{t s p q} (\Gamma_{p q} + \delta_{p q}) + \epsilon_{s n t q} (\Gamma_{n q} + \delta_{n q}) - \epsilon_{t n s q} (\Gamma_{n q} + \delta_{n q}) - \epsilon_{m n p s} (\Gamma_{m n t p} + \Gamma_{m n} \delta_{p t} - \Gamma_{m t} \delta_{n p} + \Gamma_{n t} \delta_{m p}) + \epsilon_{m n p t} (\Gamma_{m n s p} + \Gamma_{m n} \delta_{p s} - \Gamma_{m s} \delta_{n p} + \Gamma_{n s} \delta_{m p}) + \epsilon_{m s p q} (\Gamma_{m q t p} + \Gamma_{m q} \delta_{p t} - \Gamma_{m t} \delta_{p q} + \Gamma_{q t} \delta_{m p}) - \epsilon_{m t p q} (\Gamma_{m q s p} + \Gamma_{m q} \delta_{p s} - \Gamma_{m s} \delta_{p q} + \Gamma_{q s} \delta_{m p}) - \epsilon_{s n p q} (\Gamma_{n q t p} + \Gamma_{n q} \delta_{p t} - \Gamma_{n t} \delta_{p q} + \Gamma_{q t} \delta_{n p}) + \epsilon_{t n p q} (\Gamma_{n q s p} + \Gamma_{n q} \delta_{p s} - \Gamma_{n s} \delta_{p q} + \Gamma_{q s} \delta_{n p}) - \epsilon_{m t p s} (\Gamma_{m p} + \delta_{m p}) + \epsilon_{m s p t} (\Gamma_{m p} + \delta_{m p}) + \epsilon_{s t p q} (\Gamma_{q p} + \delta_{p q}) - \epsilon_{t s p q} (\Gamma_{q p} + \delta_{p q}) - \epsilon_{s n p t} (\Gamma_{n p} + \delta_{n p}) + \epsilon_{t n p s} (\Gamma_{n p} + \delta_{n p}) + \epsilon_{m n p s} (\Gamma_{m p t n} + \Gamma_{m p} \delta_{n t} - \Gamma_{m t} \delta_{n p} + \Gamma_{p t} \delta_{m n}) - \epsilon_{m n p t} (\Gamma_{m p s n} + \Gamma_{m p} \delta_{n s} - \Gamma_{m s} \delta_{n p} + \Gamma_{p s} \delta_{m n}) - \epsilon_{m n s q} (\Gamma_{m q t n} + \Gamma_{m q} \delta_{n t} - \Gamma_{m t} \delta_{n q} + \Gamma_{q t} \delta_{m n}) + \epsilon_{m n t q} (\Gamma_{m q s n} + \Gamma_{m q} \delta_{n s} - \Gamma_{m s} \delta_{n q} + \Gamma_{q s} \delta_{m n}) + \epsilon_{s n p q} (\Gamma_{p q t n} + \Gamma_{p q} \delta_{n t} - \Gamma_{p t} \delta_{n q} + \Gamma_{q t} \delta_{n p}) - \epsilon_{t n p q} (\Gamma_{p q s n} + \Gamma_{p q} \delta_{n s} - \Gamma_{p s} \delta_{n q} + \Gamma_{q s} \delta_{n p}) + \epsilon_{m n t s} (\Gamma_{m n} + \delta_{m n}) - \epsilon_{m n s t} (\Gamma_{m n} + \delta_{m n}) - \epsilon_{s n t q} (\Gamma_{q n} + \delta_{n q}) + \epsilon_{t n s q} (\Gamma_{q n} + \delta_{n q}) + \epsilon_{s n p t} (\Gamma_{p n} + \delta_{n p}) - \epsilon_{t n p s} (\Gamma_{p n} + \delta_{n p}) - \epsilon_{m n p s} (\Gamma_{n p t m} + \Gamma_{n p} \delta_{m t} - \Gamma_{n t} \delta_{m p} + \Gamma_{p t} \delta_{m n}) + \epsilon_{m n p t} (\Gamma_{n p s m} + \Gamma_{n p} \delta_{m s} - \Gamma_{n s} \delta_{m p} + \Gamma_{p s} \delta_{m n}) + \epsilon_{m n s q} (\Gamma_{n q t m} + \Gamma_{n q} \delta_{m t} - \Gamma_{n t} \delta_{m q} + \Gamma_{q t} \delta_{m n}) - \epsilon_{m n t q} (\Gamma_{n q s m} + \Gamma_{n q} \delta_{m s} - \Gamma_{n s} \delta_{m q} + \Gamma_{q s} \delta_{m n}) - \epsilon_{m s p q} (\Gamma_{p q t m} + \Gamma_{p q} \delta_{m t} - \Gamma_{p t} \delta_{m q} + \Gamma_{q t} \delta_{m p}) + \epsilon_{m t p q} (\Gamma_{p q s m} + \Gamma_{p q} \delta_{m s} - \Gamma_{p s} \delta_{m q} + \Gamma_{q s} \delta_{m p}) - \epsilon_{m n t s} (\Gamma_{n m} + \delta_{m n}) + \epsilon_{m n s t} (\Gamma_{n m} + \delta_{m n}) + \epsilon_{m s t q} (\Gamma_{q m} + \delta_{m q}) - \epsilon_{m t s q} (\Gamma_{q m} + \delta_{m q}) - \epsilon_{m s p t} (\Gamma_{p m} + \delta_{m p}) + \epsilon_{m t p s} (\Gamma_{p m} + \delta_{m p}); \end{dmath*} {\color[named]{Blue}\begin{verbatim} @distribute!(%); \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= \Gamma_{m n t q} \epsilon_{m n s q} + \Gamma_{m n} \epsilon_{m n s t} - \Gamma_{m n s q} \epsilon_{m n t q} - \Gamma_{m n} \epsilon_{m n t s} - \Gamma_{m p t q} \epsilon_{m s p q} - \Gamma_{m p} \epsilon_{m s p t} + \Gamma_{m p s q} \epsilon_{m t p q} + \Gamma_{m p} \epsilon_{m t p s} + \Gamma_{n p t q} \epsilon_{s n p q} + \Gamma_{n p} \epsilon_{s n p t} - \Gamma_{n p s q} \epsilon_{t n p q} - \Gamma_{n p} \epsilon_{t n p s} - \Gamma_{m q} \epsilon_{m t s q} + \Gamma_{m q} \epsilon_{m s t q} + \Gamma_{p q} \epsilon_{s t p q} - \Gamma_{p q} \epsilon_{t s p q} - \Gamma_{n q} \epsilon_{s n t q} + \Gamma_{n q} \epsilon_{t n s q} - \Gamma_{m n t p} \epsilon_{m n p s} + \Gamma_{m n s p} \epsilon_{m n p t} + \Gamma_{m q t p} \epsilon_{m s p q} - \Gamma_{m q s p} \epsilon_{m t p q} - \Gamma_{n q t p} \epsilon_{s n p q} + \Gamma_{n q s p} \epsilon_{t n p q} + \Gamma_{q p} \epsilon_{s t p q} - \Gamma_{q p} \epsilon_{t s p q} + \Gamma_{m p t n} \epsilon_{m n p s} - \Gamma_{m p s n} \epsilon_{m n p t} - \Gamma_{m q t n} \epsilon_{m n s q} + \Gamma_{m q s n} \epsilon_{m n t q} + \Gamma_{p q t n} \epsilon_{s n p q} - \Gamma_{p q s n} \epsilon_{t n p q} - \Gamma_{q n} \epsilon_{s n t q} + \Gamma_{q n} \epsilon_{t n s q} + \Gamma_{p n} \epsilon_{s n p t} - \Gamma_{p n} \epsilon_{t n p s} - \Gamma_{n p t m} \epsilon_{m n p s} + \Gamma_{n p s m} \epsilon_{m n p t} + \Gamma_{n q t m} \epsilon_{m n s q} - \Gamma_{n q s m} \epsilon_{m n t q} - \Gamma_{p q t m} \epsilon_{m s p q} + \Gamma_{p q s m} \epsilon_{m t p q} - \Gamma_{n m} \epsilon_{m n t s} + \Gamma_{n m} \epsilon_{m n s t} + \Gamma_{q m} \epsilon_{m s t q} - \Gamma_{q m} \epsilon_{m t s q} - \Gamma_{p m} \epsilon_{m s p t} + \Gamma_{p m} \epsilon_{m t p s}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @canonicalise!(%); \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= 3\, \Gamma_{t m n q} \epsilon_{s m n q} - 3\, \Gamma_{s m n q} \epsilon_{t m n q} + 3\, \Gamma_{t m p q} \epsilon_{s m p q} - 3\, \Gamma_{s m p q} \epsilon_{t m p q} + 3\, \Gamma_{t n p q} \epsilon_{s n p q} - 3\, \Gamma_{s n p q} \epsilon_{t n p q} + 3\, \Gamma_{t m n p} \epsilon_{s m n p} - 3\, \Gamma_{s m n p} \epsilon_{t m n p}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @rename_dummies!(%); \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= 12\, \Gamma_{t m n p} \epsilon_{s m n p} - 12\, \Gamma_{s m n p} \epsilon_{t m n p}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @decompose_product!(%): @canonicalise!(%): \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] 10\specialcolon{}= 0; \end{dmath*} \begin{verbatim} @collect_terms: not applicable. \end{verbatim} {\color[named]{Blue}\begin{verbatim} \Gamma_{r} \Gamma_{s t} \Gamma_{r}; \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] 3\specialcolon{}= \Gamma_{r} \Gamma_{s t} \Gamma_{r}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}; \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] 3\specialcolon{}= (\Gamma_{r s t} + \Gamma_{t} \delta_{r s} - \Gamma_{s} \delta_{r t}) \Gamma_{r}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @distribute!(%); \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] 3\specialcolon{}= \Gamma_{r s t} \Gamma_{r} + \Gamma_{t} \Gamma_{s} - \Gamma_{s} \Gamma_{t}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}; \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] 3\specialcolon{}= \Gamma_{r s t r} + 2\, \Gamma_{t s} + 2\, \Gamma_{s t}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @canonicalise!(%); \end{verbatim}} % orig % % end_orig \begin{dmath*}[compact, spread=2pt] 3\specialcolon{}= 0; \end{dmath*} \end{document} cadabra-1.39/examples/tutorial3.cnb000066400000000000000000000304211234107666300172630ustar00rootroot00000000000000% Cadabra notebook version 1.1 \documentclass[11pt]{article} \usepackage[textwidth=460pt, textheight=660pt]{geometry} \usepackage[usenames]{color} \usepackage{amssymb} \usepackage[parfill]{parskip} \usepackage{breqn} \usepackage{tableaux} \def\specialcolon{\mathrel{\mathop{:}}\hspace{-.5em}} \renewcommand{\bar}[1]{\overline{#1}} \begin{document} {\color[named]{Blue}\begin{verbatim} ::PostDefaultRules(@@prodsort!(%), @@rename_dummies!(%), @@canonicalise!(%), @@collect_terms!(%) ). { a,b,c,d,e }::Indices(vector). \bar{#}::DiracBar. { \partial{#}, \ppartial{#} }::PartialDerivative. { A_{a}, f_{a b} }::Depends(\partial, \ppartial). { \epsilon, \gamma_{#} }::Depends(\bar). \lambda::Depends(\bar, \partial). { \lambda, \gamma_{#} }::NonCommuting. { \lambda, \epsilon }::Spinor(dimension=4, type=Majorana). { \epsilon, \lambda }::SortOrder. { \epsilon, \lambda }::AntiCommuting. \lambda::SelfAntiCommuting. \gamma_{#}::GammaMatrix(metric=\delta). \delta{#}::Accent. f_{a b}::AntiSymmetric. \delta_{a b}::KroneckerDelta. \end{verbatim}} \begin{verbatim} Assigning property PostDefaultRules to . Assigning list property Indices to a, b, c, d, e. Assigning property DiracBar to \bar. Assigning property PartialDerivative to \partial, \ppartial. Assigning property Depends to A, f. Assigning property Depends to \epsilon, \gamma. Assigning property Depends to \lambda. Assigning list property NonCommuting to \lambda, \gamma. Assigning property Spinor to \lambda, \epsilon. Assigning list property SortOrder to \epsilon, \lambda. Assigning list property AntiCommuting to \epsilon, \lambda. Assigning property SelfAntiCommuting to \lambda. Assigning property GammaMatrix to \gamma. Assigning property Accent to \delta. Assigning property AntiSymmetric to f. Assigning property KroneckerDelta to \delta. \end{verbatim} {\color[named]{Blue}\begin{verbatim} susy:= { \delta{A_{a}} = \bar{\epsilon} \gamma_{a} \lambda, \delta{\lambda} = -(1/2) \gamma_{a b} \epsilon f_{a b} }; S:= -(1/4) f_{a b} f_{a b} - (1/2) \bar{\lambda} \gamma_{a} \partial_{a}{\lambda}; \end{verbatim}} % orig % {\delta{A_{a}} = \bar{\epsilon} \gamma_{a} \lambda, \delta{\lambda} = (-1/2) \gamma_{a b} \epsilon f_{a b}}; % end_orig \begin{dmath*}[compact, spread=2pt] susy\specialcolon{}= {\delta{A_{a}} = \bar{\epsilon} \gamma_{a} \lambda,\quad \delta{\lambda} = (\frac{-1}{2})\, \gamma_{a b} \epsilon f_{a b}}; \end{dmath*} % orig % - 1/4 f_{a b} f_{a b} - 1/2 \bar{\lambda} \gamma_{a} \partial_{a}{\lambda}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= - \frac{1}{4}\, f_{a b} f_{a b} - \frac{1}{2}\, \bar{\lambda} \gamma_{a} \partial_{a}{\lambda}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @vary!(%)( f_{a b} -> \partial_{a}{\delta{A_{b}}} - \partial_{b}{\delta{A_{a}}}, \lambda -> \delta{\lambda} ); \end{verbatim}} % orig % - 1/2 (\partial_{a}{\delta{A_{b}}} - \partial_{b}{\delta{A_{a}}}) f_{a b} - 1/2 \bar{\delta{\lambda}} \gamma_{a} \partial_{a}{\lambda} - 1/2 \bar{\lambda} \gamma_{a} \partial_{a}{\delta{\lambda}}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= - \frac{1}{2}\, (\partial_{a}{\delta{A_{b}}} - \partial_{b}{\delta{A_{a}}}) f_{a b} - \frac{1}{2}\, \bar{\delta{\lambda}} \gamma_{a} \partial_{a}{\lambda} - \frac{1}{2}\, \bar{\lambda} \gamma_{a} \partial_{a}{\delta{\lambda}}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @distribute!(%); @substitute!(%)( @(susy) ); @prodrule!(%); @distribute!(%); @unwrap!(%); @rewrite_diracbar!(%); \end{verbatim}} % orig % - \partial_{a}{\delta{A_{b}}} f_{a b} - 1/2 \bar{\delta{\lambda}} \gamma_{a} \partial_{a}{\lambda} - 1/2 \bar{\lambda} \gamma_{a} \partial_{a}{\delta{\lambda}}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= - \partial_{a}{\delta{A_{b}}} f_{a b} - \frac{1}{2}\, \bar{\delta{\lambda}} \gamma_{a} \partial_{a}{\lambda} - \frac{1}{2}\, \bar{\lambda} \gamma_{a} \partial_{a}{\delta{\lambda}}; \end{dmath*} % orig % - \partial_{a}(\bar{\epsilon} \gamma_{b} \lambda) f_{a b} + 1/4 \bar(\gamma_{a b} \epsilon f_{a b}) \gamma_{c} \partial_{c}{\lambda} - 1/2 \bar{\lambda} \gamma_{a} \partial_{a}((-1/2) \gamma_{b c} \epsilon f_{b c}); % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= - \partial_{a}(\bar{\epsilon} \gamma_{b} \lambda) f_{a b} + \frac{1}{4}\, \bar(\gamma_{a b} \epsilon f_{a b}) \gamma_{c} \partial_{c}{\lambda} - \frac{1}{2}\, \bar{\lambda} \gamma_{a} \partial_{a}((\frac{-1}{2})\, \gamma_{b c} \epsilon f_{b c}); \end{dmath*} % orig % - (\partial_{a}{\bar{\epsilon}} \gamma_{b} \lambda + \bar{\epsilon} \partial_{a}{\gamma_{b}} \lambda + \bar{\epsilon} \gamma_{b} \partial_{a}{\lambda}) f_{a b} + 1/4 \bar(\gamma_{a b} \epsilon f_{a b}) \gamma_{c} \partial_{c}{\lambda} - 1/2 \bar{\lambda} \gamma_{a} ( - 1/2 \partial_{a}{\gamma_{b c}} \epsilon f_{b c} - 1/2 \gamma_{b c} \partial_{a}{\epsilon} f_{b c} - 1/2 \gamma_{b c} \epsilon \partial_{a}{f_{b c}}); % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= - (\partial_{a}{\bar{\epsilon}} \gamma_{b} \lambda + \bar{\epsilon} \partial_{a}{\gamma_{b}} \lambda + \bar{\epsilon} \gamma_{b} \partial_{a}{\lambda}) f_{a b} + \frac{1}{4}\, \bar(\gamma_{a b} \epsilon f_{a b}) \gamma_{c} \partial_{c}{\lambda} - \frac{1}{2}\, \bar{\lambda} \gamma_{a} ( - \frac{1}{2}\, \partial_{a}{\gamma_{b c}} \epsilon f_{b c} - \frac{1}{2}\, \gamma_{b c} \partial_{a}{\epsilon} f_{b c} - \frac{1}{2}\, \gamma_{b c} \epsilon \partial_{a}{f_{b c}}); \end{dmath*} % orig % - \partial_{a}{\bar{\epsilon}} \gamma_{b} \lambda f_{a b} - \bar{\epsilon} \partial_{a}{\gamma_{b}} \lambda f_{a b} + \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} + 1/4 \bar(\gamma_{a b} \epsilon f_{a b}) \gamma_{c} \partial_{c}{\lambda} + 1/4 \bar{\lambda} \gamma_{a} \partial_{a}{\gamma_{b c}} \epsilon f_{b c} + 1/4 \bar{\lambda} \gamma_{a} \gamma_{b c} \partial_{a}{\epsilon} f_{b c} + 1/4 \bar{\lambda} \gamma_{a} \gamma_{b c} \epsilon \partial_{a}{f_{b c}}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= - \partial_{a}{\bar{\epsilon}} \gamma_{b} \lambda f_{a b} - \bar{\epsilon} \partial_{a}{\gamma_{b}} \lambda f_{a b} + \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} + \frac{1}{4}\, \bar(\gamma_{a b} \epsilon f_{a b}) \gamma_{c} \partial_{c}{\lambda} + \frac{1}{4}\, \bar{\lambda} \gamma_{a} \partial_{a}{\gamma_{b c}} \epsilon f_{b c} + \frac{1}{4}\, \bar{\lambda} \gamma_{a} \gamma_{b c} \partial_{a}{\epsilon} f_{b c} + \frac{1}{4}\, \bar{\lambda} \gamma_{a} \gamma_{b c} \epsilon \partial_{a}{f_{b c}}; \end{dmath*} % orig % \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} + 1/4 \bar(\gamma_{a b} \epsilon) \gamma_{c} \partial_{c}{\lambda} f_{a b} + 1/4 \bar{\lambda} \gamma_{a} \gamma_{b c} \epsilon \partial_{a}{f_{b c}}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} + \frac{1}{4}\, \bar(\gamma_{a b} \epsilon) \gamma_{c} \partial_{c}{\lambda} f_{a b} + \frac{1}{4}\, \bar{\lambda} \gamma_{a} \gamma_{b c} \epsilon \partial_{a}{f_{b c}}; \end{dmath*} % orig % \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} - 1/4 \bar{\epsilon} \gamma_{a b} \gamma_{c} \partial_{c}{\lambda} f_{a b} + 1/4 \bar{\lambda} \gamma_{a} \gamma_{b c} \epsilon \partial_{a}{f_{b c}}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} - \frac{1}{4}\, \bar{\epsilon} \gamma_{a b} \gamma_{c} \partial_{c}{\lambda} f_{a b} + \frac{1}{4}\, \bar{\lambda} \gamma_{a} \gamma_{b c} \epsilon \partial_{a}{f_{b c}}; \end{dmath*} \begin{verbatim} Warning: assuming Minkowski signature. \end{verbatim} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( \partial_{c}{f_{a b}} -> \ppartial_{c}{f_{a b}} ): @pintegrate!(%){\ppartial}: @rename!(%){"\ppartial"}{"\partial"}: @prodrule!(%); @unwrap!(%); \end{verbatim}} % orig % \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} - 1/4 \bar{\epsilon} \gamma_{a b} \gamma_{c} \partial_{c}{\lambda} f_{a b} - 1/4 (\partial_{a}{\bar{\lambda}} \gamma_{a} \gamma_{b c} \epsilon + \bar{\lambda} \partial_{a}{\gamma_{a}} \gamma_{b c} \epsilon + \bar{\lambda} \gamma_{a} \partial_{a}{\gamma_{b c}} \epsilon + \bar{\lambda} \gamma_{a} \gamma_{b c} \partial_{a}{\epsilon}) f_{b c}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} - \frac{1}{4}\, \bar{\epsilon} \gamma_{a b} \gamma_{c} \partial_{c}{\lambda} f_{a b} - \frac{1}{4}\, (\partial_{a}{\bar{\lambda}} \gamma_{a} \gamma_{b c} \epsilon + \bar{\lambda} \partial_{a}{\gamma_{a}} \gamma_{b c} \epsilon + \bar{\lambda} \gamma_{a} \partial_{a}{\gamma_{b c}} \epsilon + \bar{\lambda} \gamma_{a} \gamma_{b c} \partial_{a}{\epsilon}) f_{b c}; \end{dmath*} % orig % \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} - 1/4 \bar{\epsilon} \gamma_{a b} \gamma_{c} \partial_{c}{\lambda} f_{a b} - 1/4 \partial_{a}{\bar{\lambda}} \gamma_{a} \gamma_{b c} \epsilon f_{b c}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} - \frac{1}{4}\, \bar{\epsilon} \gamma_{a b} \gamma_{c} \partial_{c}{\lambda} f_{a b} - \frac{1}{4}\, \partial_{a}{\bar{\lambda}} \gamma_{a} \gamma_{b c} \epsilon f_{b c}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}; @distribute!(%); @eliminate_kr!(%); @substitute!(%)( \partial_{a}{\bar{\lambda}} -> \bar{\partial_{a}{\lambda}} ); @spinorsort!(%); \end{verbatim}} % orig % \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} - 1/4 \bar{\epsilon} (\gamma_{a b c} + \delta_{b c} \gamma_{a} - \delta_{a c} \gamma_{b}) \partial_{c}{\lambda} f_{a b} - 1/4 \partial_{a}{\bar{\lambda}} (\gamma_{a b c} + \delta_{a b} \gamma_{c} - \delta_{a c} \gamma_{b}) \epsilon f_{b c}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} - \frac{1}{4}\, \bar{\epsilon} (\gamma_{a b c} + \delta_{b c} \gamma_{a} - \delta_{a c} \gamma_{b}) \partial_{c}{\lambda} f_{a b} - \frac{1}{4}\, \partial_{a}{\bar{\lambda}} (\gamma_{a b c} + \delta_{a b} \gamma_{c} - \delta_{a c} \gamma_{b}) \epsilon f_{b c}; \end{dmath*} % orig % \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} - 1/4 \bar{\epsilon} \gamma_{a b c} \partial_{a}{\lambda} f_{b c} + 1/2 \bar{\epsilon} \delta_{a b} \gamma_{c} \partial_{a}{\lambda} f_{b c} - 1/4 \partial_{a}{\bar{\lambda}} \gamma_{a b c} \epsilon f_{b c} - 1/2 \delta_{a b} \partial_{a}{\bar{\lambda}} \gamma_{c} \epsilon f_{b c}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} - \frac{1}{4}\, \bar{\epsilon} \gamma_{a b c} \partial_{a}{\lambda} f_{b c} + \frac{1}{2}\, \bar{\epsilon} \delta_{a b} \gamma_{c} \partial_{a}{\lambda} f_{b c} - \frac{1}{4}\, \partial_{a}{\bar{\lambda}} \gamma_{a b c} \epsilon f_{b c} - \frac{1}{2}\, \delta_{a b} \partial_{a}{\bar{\lambda}} \gamma_{c} \epsilon f_{b c}; \end{dmath*} % orig % 1/2 \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} - 1/4 \bar{\epsilon} \gamma_{a b c} \partial_{a}{\lambda} f_{b c} - 1/4 \partial_{a}{\bar{\lambda}} \gamma_{a b c} \epsilon f_{b c} - 1/2 \partial_{a}{\bar{\lambda}} \gamma_{b} \epsilon f_{a b}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= \frac{1}{2}\, \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} - \frac{1}{4}\, \bar{\epsilon} \gamma_{a b c} \partial_{a}{\lambda} f_{b c} - \frac{1}{4}\, \partial_{a}{\bar{\lambda}} \gamma_{a b c} \epsilon f_{b c} - \frac{1}{2}\, \partial_{a}{\bar{\lambda}} \gamma_{b} \epsilon f_{a b}; \end{dmath*} % orig % 1/2 \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} - 1/4 \bar{\epsilon} \gamma_{a b c} \partial_{a}{\lambda} f_{b c} - 1/4 \bar{\partial_{a}{\lambda}} \gamma_{a b c} \epsilon f_{b c} - 1/2 \bar{\partial_{a}{\lambda}} \gamma_{b} \epsilon f_{a b}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= \frac{1}{2}\, \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} - \frac{1}{4}\, \bar{\epsilon} \gamma_{a b c} \partial_{a}{\lambda} f_{b c} - \frac{1}{4}\, \bar{\partial_{a}{\lambda}} \gamma_{a b c} \epsilon f_{b c} - \frac{1}{2}\, \bar{\partial_{a}{\lambda}} \gamma_{b} \epsilon f_{a b}; \end{dmath*} % orig % (-1/2) \bar{\epsilon} \gamma_{a b c} \partial_{a}{\lambda} f_{b c}; % end_orig \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= (\frac{-1}{2})\, \bar{\epsilon} \gamma_{a b c} \partial_{a}{\lambda} f_{b c}; \end{dmath*} \end{document} cadabra-1.39/examples/young_tableaux.cnb000066400000000000000000000043241234107666300203660ustar00rootroot00000000000000% Cadabra notebook version 1.1 \documentclass[11pt]{article} \usepackage[textwidth=460pt, textheight=660pt]{geometry} \usepackage[usenames]{color} \usepackage{amssymb} \usepackage[parfill]{parskip} \usepackage{breqn} \usepackage{tableaux} \def\specialcolon{\mathrel{\mathop{:}}\hspace{-.5em}} \renewcommand{\bar}[1]{\overline{#1}} \begin{document} {\color[named]{Blue}\begin{verbatim} \tableau{#}::Tableau(dimension=10). \end{verbatim}} % Begin TeX comment Assigning property Tableau to $\tableau{1} $. \\ % End TeX comment {\color[named]{Blue}\begin{verbatim} \tableau{2}{2} \tableau{2}{2}; \end{verbatim}} % orig % \tableau{2 2} \tableau{2 2} % end_orig \begin{dmath*}[compact, spread=2pt] 1\specialcolon{}= \tableau{2 2} \tableau{2 2}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @lr_tensor!(%); \end{verbatim}} % orig % \tableau{4 4} + \tableau{4 3 1} + \tableau{4 2 2} + \tableau{3 3 1 1} + \tableau{3 2 2 1} + \tableau{2 2 2 2} % end_orig \begin{dmath*}[compact, spread=2pt] 1\specialcolon{}= \tableau{4 4} + \tableau{4 3 1} + \tableau{4 2 2} + \tableau{3 3 1 1} + \tableau{3 2 2 1} + \tableau{2 2 2 2}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} \ftableau{#}::FilledTableau(dimension=10). \end{verbatim}} % Begin TeX comment Assigning property FilledTableau to $\ftableau{{\#}} $. \\ % End TeX comment {\color[named]{Blue}\begin{verbatim} \ftableau{0,0}{1,1} \ftableau{a,a}{b,b}; \end{verbatim}} % orig % \ftableau{{0}{0},{1}{1}} \ftableau{{a}{a},{b}{b}} % end_orig \begin{dmath*}[compact, spread=2pt] 3\specialcolon{}= \ftableau{{0}{0},{1}{1}} \ftableau{{a}{a},{b}{b}}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @lr_tensor!(%); \end{verbatim}} % orig % (\ftableau{{0}{0}{a}{a},{1}{1}{b}{b}} + \ftableau{{0}{0}{a}{a},{1}{1}{b},{b}} + \ftableau{{0}{0}{a}{a},{1}{1},{b}{b}} + \ftableau{{0}{0}{a},{1}{1}{b},{a},{b}} + \ftableau{{0}{0}{a},{1}{1},{a}{b},{b}} + \ftableau{{0}{0},{1}{1},{a}{a},{b}{b}}) % end_orig \begin{dmath*}[compact, spread=2pt] 3\specialcolon{}= (\ftableau{{0}{0}{a}{a},{1}{1}{b}{b}} + \ftableau{{0}{0}{a}{a},{1}{1}{b},{b}} + \ftableau{{0}{0}{a}{a},{1}{1},{b}{b}} + \ftableau{{0}{0}{a},{1}{1}{b},{a},{b}} + \ftableau{{0}{0}{a},{1}{1},{a}{b},{b}} + \ftableau{{0}{0},{1}{1},{a}{a},{b}{b}}); \end{dmath*} \end{document} cadabra-1.39/gui/000077500000000000000000000000001234107666300136175ustar00rootroot00000000000000cadabra-1.39/gui/Makefile.in000066400000000000000000000030601234107666300156630ustar00rootroot00000000000000 .PHONY: all MACTEST= @MAC_OS_X@ all: xcadabra static: xcadabra_static OBJS = help.o widgets.o window.o main.o ../src/stopwatch.o CFLAGS = -O2 -I. -I@top_srcdir@/include `pkg-config modglue --cflags` `pkg-config --cflags gtkmm-2.4` \ `pkg-config --cflags pango` SRCS = `find . -name "*.cc"` TIMESTAMP = -D"RELEASE=\"${RELEASE}\"" -D"DATETIME=\"`date | sed -e 's/ / /'`\"" -DHOSTNAME=\"`hostname`\" %.o: %.cc @CXX@ -Wall @CFLAGS@ -D"DESTDIR=\"@prefix@\"" ${TIMESTAMP} ${CFLAGS} -c -o $@ $< main.o: $(OBJS) Makefile xcadabra: $(OBJS) @CXX@ -o xcadabra $+ `pkg-config modglue --libs` `pkg-config --libs gtkmm-2.4` -lpcrecpp xcadabra_static: $(OBJS) @CXX@ -o xcadabra -static $+ -L@prefix@/lib `pkg-config modglue --libs` \ `pkg-config --libs gtkmm-2.4` `pkg-config libxml++-2.6` \ -lpthread -lexpat test_texit: texit.o test_texit.o @CXX@ -o test_texit `pkg-config modglue --libs` `pkg-config --libs gtkmm-2.4` $+ install: ifeq ($(strip $(MACTEST)),) strip xcadabra endif install -d ${DESTDIR}@prefix@/bin install -m 0755 xcadabra ${DESTDIR}@prefix@/bin install -d ${DESTDIR}@prefix@/share/texmf/tex/latex/cadabra install -m 644 tableaux.sty $(DESTDIR)@prefix@/share/texmf/tex/latex/cadabra/tableaux.sty uninstall: rm -f ${DESTDIR}@prefix@/bin/xcadabra clean: rm -f *~ *.o xcadabra spawner multi distclean: clean rm -f Makefile .depend .depend: rm -f .depend for i in ${SRCS}; \ do g++ -E -MM -MT `echo $$i | sed -e 's/\.\///' -e 's/\.cc/\.o/'` ${CFLAGS} $$i >> .depend; \ done include .depend cadabra-1.39/gui/cadabra.el000066400000000000000000000025721234107666300155240ustar00rootroot00000000000000;; ;; Cadabra: a field-theory motivated computer algebra system. ;; Copyright (C) 2001-2009 Kasper Peeters ;; ;; 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 3 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, see . ;; (defun cadabra-insertion-filter (proc string) (with-current-buffer (process-buffer proc) (let ((moving (= (point) (process-mark proc)))) (save-excursion ;; Insert the text, advancing the process marker. (goto-char (process-mark proc)) (insert string) (set-marker (process-mark proc) (point))) (if moving (goto-char (process-mark proc)))))) (setq cdbproc (start-process "cadabra" "cadabra" "cadabra")) (process-send-string cdbproc "@algorithms;\n") \begin{cdb} W_{a b c d} W_{e d e g}; @canonicalise!(%); % W_{a b c d} W_{e d e g}; \end{cdb}cadabra-1.39/gui/caslink.hh000066400000000000000000000003241234107666300155630ustar00rootroot00000000000000 #ifndef caslink_hh__ #define caslink_hh__ class CASLink { public: private: void received_expression(const std::string&); void received_texcomment(const std::string&); void input_ended(); }; #endif cadabra-1.39/gui/help.cc000066400000000000000000000172421234107666300150640ustar00rootroot00000000000000/* Cadabra: a field-theory motivated computer algebra system. Copyright (C) 2001-2011 Kasper Peeters 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 3 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, see . */ #include "help.hh" #include #include #ifdef __CYGWIN__ #include #include #endif #include #include CadabraHelp::CadabraHelp() : history_pos(-1), buttonbox(0), back(Gtk::Stock::GO_BACK), forward(Gtk::Stock::GO_FORWARD) { set_title("XCadabra help"); try { set_icon_from_file(DESTDIR+std::string("/share/pixmaps/cadabra.png")); } catch(Glib::FileError fe) { std::cerr << "cannot open " << DESTDIR+std::string("/share/pixmaps/cadabra.png") << std::endl; } set_gravity(Gdk::GRAVITY_NORTH_EAST); set_default_size((std::min)(Gdk::Screen::get_default()->get_width()-20, 600), (std::min)(Gdk::Screen::get_default()->get_height()-20, 800)); add(topbox); topbox.pack_start(navbox, Gtk::PACK_SHRINK); // actiongroup=Gtk::ActionGroup::create(); // actiongroup->add( Gtk::Action::create("MenuFile", "_File") ); // actiongroup->add( Gtk::Action::create("CloseWindow", Gtk::Stock::CLOSE), // sigc::mem_fun(doc, &XCadabra::on_help_close) ); // uimanager = Gtk::UIManager::create(); // uimanager->insert_action_group(actiongroup); // add_accel_group(uimanager->get_accel_group()); // // Glib::ustring ui_info = // "" // " " // " " // " " // " " // " " // ""; // // uimanager->add_ui_from_string(ui_info); // Gtk::Widget *menubar = uimanager->get_widget("/MenuBar"); // topbox.pack_start(*menubar, Gtk::PACK_SHRINK); navbox.pack_start(back, Gtk::PACK_SHRINK); navbox.pack_start(forward, Gtk::PACK_SHRINK); back.set_sensitive(false); forward.set_sensitive(false); back.signal_clicked().connect(sigc::mem_fun(*this, &CadabraHelp::on_back)); forward.signal_clicked().connect(sigc::mem_fun(*this, &CadabraHelp::on_forward)); topbox.add(scroll); scroll.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS); scroll.set_border_width(1); scroll.add(scrollbox); // Set-up the TeXView widget textbuf=Gtk::TextBuffer::create(); texbuf=TeXBuffer::create(textbuf, tex_engine_help); texview=new TeXView(texbuf, 12); scrollbox.pack_start(*texview, Gtk::PACK_EXPAND_WIDGET, 0); // show_all(); } void CadabraHelp::display_help(objtype_t objtype, const std::string& objname) { if(history.size()>0 && history.back()==std::make_pair(objtype, objname)) { show_all(); return; // already displaying this one } history.resize(history_pos+1); history.push_back(std::make_pair(objtype, objname)); history_pos=history.size()-1; display_help(); } void CadabraHelp::display_help() { show_all(); // Add the buttons for related topics if(buttonbox!=0) { topbox.remove(*buttonbox); delete buttonbox; } buttonbox = new Gtk::HBox; topbox.pack_start(*buttonbox, Gtk::PACK_SHRINK); relatedlabel.set_label("See also: "); buttonbox->pack_start(relatedlabel, Gtk::PACK_SHRINK); back.set_sensitive(history.size()>1); forward.set_sensitive(history_pos+1(history.size())); std::string fname; std::string prefix; #ifdef __CYGWIN__ TCHAR path[MAX_PATH]; GetModuleFileName(NULL, path, MAX_PATH); prefix=path; prefix=prefix.substr(0,prefix.size() -std::string("xcadabra.exe").size()); pcrecpp::RE(":\\\\").GlobalReplace("/", &prefix); pcrecpp::RE("\\\\").GlobalReplace("/", &prefix); prefix="/cygdrive/"+prefix+"/doc"; #else prefix=DESTDIR+std::string("/share/doc/cadabra"); #endif switch(history[history_pos].first) { case t_property: fname=prefix+std::string("/properties/"); break; case t_algorithm: fname=prefix+std::string("/algorithms/"); break; case t_texcommand: fname=prefix+std::string("/reserved/"); break; default: fname=prefix+std::string("/general"); break; } fname+=history[history_pos].second+".tex"; // std::cout << fname << std::endl; std::string total, line; std::ifstream helpfile(fname.c_str()); if(helpfile.is_open()==false) { total = "Sorry, no help available for {\\tt "+texify(history[history_pos].second)+"}.\n\n" + "{\\small (Could not open {\\tt "+texify(fname)+"}.)}"; helpfile.open((DESTDIR+std::string("/share/doc/cadabra/general.tex")).c_str()); if(helpfile.is_open()==false) { textbuf->set_text(total); texbuf->generate("",""); texview->image.set(texbuf->get_pixbuf()); return; } } std::vector seeprop, seealgo; while(std::getline(helpfile, line)) { total+=line+"\n"; if(line.substr(0,11)=="\\cdbseeprop") seeprop.push_back(line.substr(12,line.size()-13)); if(line.substr(0,11)=="\\cdbseealgo") seealgo.push_back(line.substr(12,line.size()-13)); } // for(unsigned int i=0; iset_text(total); try { texbuf->generate("",""); } catch(std::exception& ex) { Gtk::MessageDialog md(ex.what()); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); md.run(); } texview->image.set(texbuf->get_pixbuf()); for(unsigned int i=0; isignal_clicked().connect(sigc::bind( sigc::mem_fun(*this, &CadabraHelp::on_help_context_link), t_property, seeprop[i])); buttonbox->pack_start(*tmp, Gtk::PACK_SHRINK); // FIXME: is this leaking? tmp->show_all(); } for(unsigned int i=0; isignal_clicked().connect(sigc::bind( sigc::mem_fun(*this, &CadabraHelp::on_help_context_link), t_algorithm, seealgo[i])); buttonbox->pack_start(*tmp, Gtk::PACK_SHRINK); // FIXME: is this leaking? tmp->show_all(); } buttonbox->show_all(); } bool CadabraHelp::on_delete_event(GdkEventAny*) { on_help_close(); return true; } void CadabraHelp::on_back() { if(history_pos>0) { --history_pos; display_help(); } } void CadabraHelp::on_forward() { if(history_pos+1(history.size())) { ++history_pos; display_help(); } } void CadabraHelp::on_help_context_link(CadabraHelp::objtype_t objtype, std::string helpname) { display_help(objtype, helpname); } void CadabraHelp::on_help_close() { hide_all(); } bool CadabraHelp::on_configure_event(GdkEventConfigure *cfg) { tex_engine_help.set_geometry(cfg->width-20-35); bool ret=Gtk::Window::on_configure_event(cfg); texview->image.set(texbuf->get_pixbuf()); return ret; } bool CadabraHelp::on_key_press_event(GdkEventKey* event) { // std::cerr << event->keyval << " " << event->state << std::endl; if(event->keyval=='w' && event->state&Gdk::CONTROL_MASK) { hide_all(); return true; } return Window::on_key_press_event(event); } cadabra-1.39/gui/help.hh000066400000000000000000000042401234107666300150700ustar00rootroot00000000000000/* Cadabra: a field-theory motivated computer algebra system. Copyright (C) 2001-2011 Kasper Peeters 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 3 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, see . */ #ifndef help_hh__ #define help_hh__ #include #include #include #include #include #include #include #include "widgets.hh" /// The help browser window is separate from the main window. class CadabraHelp : public Gtk::Window { public: CadabraHelp(); enum objtype_t { t_none=0, t_property=1, t_algorithm=2, t_texcommand=3 }; void on_help_context_link(CadabraHelp::objtype_t, std::string); void on_help_close(); virtual bool on_configure_event(GdkEventConfigure *); void display_help(objtype_t, const std::string& obj); void display_help(); std::string texify(const std::string& str) const; virtual bool on_key_press_event(GdkEventKey *); std::vector > history; int history_pos; private: virtual bool on_delete_event(GdkEventAny*); void on_back(); void on_forward(); Gtk::VBox topbox; Gtk::HBox *buttonbox; Gtk::Label relatedlabel; Gtk::HBox navbox; Gtk::Button back, forward; Glib::RefPtr actiongroup; Glib::RefPtr uimanager; Gtk::ScrolledWindow scroll; Gtk::VBox scrollbox; Glib::RefPtr textbuf; Glib::RefPtr texbuf; TeXView *texview; }; #endif cadabra-1.39/gui/main.cc000066400000000000000000000100311234107666300150450ustar00rootroot00000000000000/* Cadabra: a field-theory motivated computer algebra system. Copyright (C) 2001-2011 Kasper Peeters 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 3 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, see . */ #include #include #include #include #include #include #include #include #include #include #ifdef __CYGWIN__ #include #endif #include "window.hh" std::map connections; std::ofstream debugout; int main (int argc, char *argv[]) { // Open the debug output file, if requested. char hostname[256]; gethostname(hostname, 255); char *pbs_job=getenv("PBS_JOBID"); std::string logname=std::string("cdb_")+hostname+(pbs_job==0?"":std::string("_")+pbs_job) +std::string(".log"); char *cdblog=getenv("CDB_LOG"); if(cdblog==0) debugout.open("/dev/null", std::ios::app); else switch(atoi(cdblog)) { case 1: debugout.open(logname.c_str(), std::ios::app); break; case 2: debugout.open("/dev/tty", std::ios::app); break; } // Setup path for tableaux.sty char *texinp=getenv("TEXINPUTS"); std::string oldpath; if(texinp!=0) oldpath=std::string(texinp); oldpath=std::string(DESTDIR)+std::string("/share/texmf/tex/latex/cadabra:")+oldpath; setenv("TEXINPUTS", oldpath.c_str(), 1); // Ensure correct installation. // if(!verify_breqn_tableaux_presence()) // return -1; // Startup Gtkmm and the GUI Gtk::Main kit(&argc, &argv); modglue::main mm(argc, argv); // Set the environment for cadabra. // setenv("CDB_USE_UTF8", "1", 1); unsetenv("CDB_PRINTSTAR");//, "false", 1); // Argument parsing std::string filename; if(argc>1) filename=argv[1]; #ifdef __CYGWIN__ std::string cdbname; TCHAR path[MAX_PATH]; GetModuleFileName(NULL, path, MAX_PATH); cdbname=path; cdbname=cdbname.substr(0,cdbname.size() -std::string("xcadabra.exe").size()) + "cadabra"; pcrecpp::RE(":\\\\").GlobalReplace("/", &cdbname); pcrecpp::RE("\\\\").GlobalReplace("/", &cdbname); cdbname="/cygdrive/"+cdbname; #else std::string cdbname="cadabra"; #endif modglue::ext_process ls_proc(cdbname); ls_proc << "--xcadabra" << "--bare" << "--nowarnings"; ls_proc.setup_pipes(); // FIXME: need cleaner error messages if this is forgotten mm.add(&ls_proc); // Setup TeX engine parameters tex_engine_help.latex_packages.push_back("cadabra"); tex_engine_main.latex_packages.push_back("breqn"); XCadabra theiface(ls_proc, filename, &mm); // Setup pipes ls_proc.input_pipe("stdout")->receiver.connect(sigc::mem_fun(theiface, &XCadabra::receive)); ls_proc.input_pipe("stderr")->receiver.connect(sigc::mem_fun(theiface, &XCadabra::receive_err)); mm.process_died.connect(sigc::mem_fun(theiface, &XCadabra::on_kernel_exit)); // FIXME: if we run this afterwards, the pipes are not setup yet. Note: this also // means that if we want to start a program while in the main loop, we have to // do this connecting business again. For the time being, let cadabra run forever // and don't worry too much about this. ls_proc.fork(); // FIXME: need error message upon failure *(ls_proc.output_pipe("stdin")) << "@print_status{true};\n@properties;\n@algorithms;\n@reserved;\n" << std::flush; theiface.connect_io_signals(); // If done this way, we miss signals if the process exits before // the main loop is entered. Well, cadabra doesn't do that. // mm.run(0); Gtk::Main::run(); return 0; } cadabra-1.39/gui/mathtex_cpp.pyx000066400000000000000000000000231234107666300166700ustar00rootroot00000000000000cdef public struct cadabra-1.39/gui/render.py000066400000000000000000000042641234107666300154560ustar00rootroot00000000000000#!/usr/bin/env python # render.py # Experiments with using the mathtext expression rendering library # on top of a cairo drawing surface. # # based on # # http://code.google.com/p/mathtex/ # http://gsoc-mathtex.blogspot.com/ # # http://www.oluyede.org/blog/writing-a-widget-using-cairo-and-pygtk-28/ # http://www.tortall.net/mu/wiki/PyGTKCairoTutorial import pygtk import gtk, gobject, cairo from mathtex.parser import MathtexParser from mathtex.boxmodel import ship from mathtex.fonts import BakomaFonts from mathtex.fonts import StixFonts from mathtex.backends.backend_cairo import MathtexBackendCairo class MathCell(gtk.DrawingArea): """Cell for display of maths.""" __gsignals__ = { "expose-event": "override" } def __init__(self): gtk.DrawingArea.__init__(self) self.parser = MathtexParser() self.bakoma = BakomaFonts() self.stix = StixFonts() # # self.parser.parse(r"$R_{\mu\nu\rho}{}^{\sigma} = \nabla_\mu F_{\nu\rho}^\sigma$", self.box = \ self.parser.parse(r"$x_{1,2}=\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$", self.bakoma, 18, 99.0) self.rects, self.glyphs, self.bbox = ship(0, 0, self.box) def do_expose_event(self, event): cr = self.window.cairo_create() cr.rectangle(event.area.x, event.area.y, event.area.width, event.area.height) cr.clip() width = self.bbox[2] - self.bbox[0] height = self.box.height depth = self.box.depth backend = MathtexBackendCairo() backend.set_canvas_size(self.box.width, self.box.height, self.box.depth, 100) backend.render(self.glyphs, self.rects) backend.render_to_context(cr) # self.draw(cr, *self.window.get_size()) def draw(self, cr, width, height): cr.set_source_rgb(0.5, 0.5, 0.7) cr.rectangle(0.5, 0.5, .5*width, .5*height) cr.fill() def run(Widget): window = gtk.Window() window.connect("delete-event", gtk.main_quit) widget = MathCell() widget.show() window.add(widget) window.present() gtk.main() if __name__ == "__main__": run(MathCell) cadabra-1.39/gui/tableaux.sty000066400000000000000000000055271234107666300161760ustar00rootroot00000000000000% % tableaux.sty version 1.0 % Copyright (C) 2007 by Kasper Peeters % % A LaTeX style file for drawing Young diagrams and Young tableaux. % % This file is part of the Cadabra computer algebra system, % % http://www.aei.mpg.de/~peekas/cadabra/ % % but may be distributed /or modified under the conditions of the % LaTeX Project Public License, either version 1.3 of this license or % (at your option) any later version. The latest version of this % license is in % % http://www.latex-project.org/lppl.txt % % and version 1.3 or later is part of all distributions of LaTeX % version 2005/12/01 or later. % % This work has the LPPL maintenance status `maintained'. % The current maintainer of this work is Kasper Peeters. % \def\@tabforc#1#2#3{\expandafter\tabf@rc\expandafter#1{#2 \^}{#3}} \def\tabf@@rc#1#2#3\tabf@@rc#4{\def#1{#2}#4\tabf@rc#1{#3}{#4}} \long\def\ReturnAfterFi#1\fi{\fi#1} \def\tabf@rc#1#2#3{% \def\temp@ty{#2}% \ifx\@empty\temp@ty \else \ReturnAfterFi{% \tabf@@rc#1#2\tabf@@rc{#3}% }% \fi }% % Sorry, some global registers... \newdimen\ytsize\ytsize=2mm \newdimen\ytfsize\ytfsize=4mm \newcount\repcnt \newdimen\acchspace \newdimen\accvspace \newdimen\raiseh \newdimen\maxw \newcommand\phrule[1]{\hbox{\vbox to0pt{\hrule height .2pt width#1\vss}}} %\newcommand\pvrule{\vbox{\hbox to0pt{\vrule width .2pt height\ytsize\hss}}} \newcommand\ftableau[1]{% \def\ctest{,} \def\Ktest{\^} \acchspace=0ex \accvspace=0ex \maxw=0ex \vbox{\hbox{% \@tabforc\thisel{#1}{% \ifx\thisel\Ktest{% \ifnum\maxw=0\maxw=\acchspace\fi% \raisebox{\accvspace}{\vbox to \ytfsize{\hbox to 0pt{\vrule height \ytfsize\hss}}}\kern\acchspace\kern-\maxw} \else\ifx\thisel\ctest \ifnum\maxw=0\maxw=\acchspace\fi% \raisebox{\accvspace}{\vbox to \ytfsize{\hbox to 0pt{\vrule height \ytfsize\hss}}}% \kern\acchspace\acchspace=0ex \advance\accvspace by -\ytfsize \else \setbox3=\hbox{$\thisel$}% \raiseh=\ytfsize% \advance\raiseh by -1ex% \divide\raiseh by 2% \advance\acchspace by-\ytfsize% \raisebox{\accvspace}{\vbox to \ytfsize{\hrule\hbox to% \ytfsize{\vrule height \ytfsize\hskip.5ex% \raisebox{\raiseh}{\tiny$\thisel$}\hss}\vss\phrule{\ytfsize}}}% \fi\fi}}}} \newcommand\tableau[1]{% \def\stest{ } \def\Ktest{\^} \acchspace=0ex \accvspace=0ex \maxw=0ex \hbox{% \@tabforc\thisel{#1}{% \ifx\thisel\Ktest{} \else \repcnt=\thisel% \loop{}% \advance\acchspace by-\ytsize% \raisebox{\accvspace}{\vbox to \ytsize{\hrule \hbox to% \ytsize{\vrule height \ytsize\hss}\vss\phrule{\ytsize}}}% \advance\repcnt by -1\ifnum\repcnt>1{}\repeat% \ifnum\maxw=0\maxw=\acchspace\fi% \raisebox{\accvspace}{\vbox to \ytsize{\hbox to 0pt{\vrule height \ytsize\hss}}}% \kern\acchspace\acchspace=0ex% \advance\accvspace by -\ytsize% \fi}\kern-\maxw}} cadabra-1.39/gui/tutorial3.cnb000066400000000000000000000124671234107666300162430ustar00rootroot00000000000000% Cadabra notebook version 1.0 \documentclass[11pt]{article} \usepackage{geometry} \usepackage[usenames]{color} \usepackage[parfill]{parskip} \usepackage{breqn} \def\specialcolon{\mathrel{\mathop{:}}\hspace{-.5em}} \renewcommand{\bar}[1]{\overline{#1}} \begin{document} % Begin TeX cell closed {\Large\bfseries Superinvariance of super QED} This notebook shows how to deal with spinors and gamma matrix algebra. % End TeX cell {\color[named]{Blue}\begin{verbatim} { a,b,c,d,e }::Indices(vector). \bar{#}::DiracBar. { \partial{#}, \ppartial{#} }::PartialDerivative. { A_{a}, f_{a b} }::Depends(\partial, \ppartial). { \epsilon, \gamma_{#} }::Depends(\bar). \lambda::Depends(\bar, \partial). { \lambda, \gamma_{#} }::NonCommuting. { \lambda, \epsilon }::Spinor(dimension=4, type=Majorana). { \epsilon, \lambda }::SortOrder. { \epsilon, \lambda }::AntiCommuting. \lambda::SelfAntiCommuting. \gamma_{#}::GammaMatrix(metric=\delta). \delta{#}::Accent. f_{a b}::AntiSymmetric. \delta_{a b}::KroneckerDelta. \end{verbatim}} \begin{verbatim} Assigning property Indices to a, b, c, d, e. Assigning property DiracBar to \bar. Assigning property PartialDerivative to \partial, \ppartial. Assigning property Depends to A, f. Assigning property Depends to \epsilon, \gamma. Assigning property Depends to \lambda. Assigning property NonCommuting to \lambda, \gamma. Assigning property Spinor to \lambda, \epsilon. Assigning property SortOrder to \epsilon, \lambda. Assigning property AntiCommuting to \epsilon, \lambda. Assigning property SelfAntiCommuting to \lambda. Assigning property GammaMatrix to \gamma. Assigning property Accent to \delta. Assigning property AntiSymmetric to f. Assigning property KroneckerDelta to \delta. \end{verbatim} {\color[named]{Blue}\begin{verbatim} ::PostDefaultRules(@@prodsort!(%), @@rename_dummies!(%), @@canonicalise!(%), @@collect_terms!(%) ). \end{verbatim}} \begin{verbatim} Assigning property PostDefaultRules to . \end{verbatim} {\color[named]{Blue}\begin{verbatim} susy:= { \delta{A_{a}} = \bar{\epsilon} \gamma_{a} \lambda, \delta{\lambda} = -(1/2) \gamma_{a b} \epsilon f_{a b} }; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] susy\specialcolon{}= \{\delta{A_{a}} = \bar{\epsilon} \gamma_{a} \lambda, \delta{\lambda} = (\frac{-1}{2})\, \gamma_{a b} \epsilon f_{a b}\}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} S:= -(1/4) f_{a b} f_{a b} - (1/2) \bar{\lambda} \gamma_{a} \partial_{a}{\lambda}; \end{verbatim}} \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= - \frac{1}{4}\, f_{a b} f_{a b} - \frac{1}{2}\, \bar{\lambda} \gamma_{a} \partial_{a}{\lambda}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @vary!(%)( f_{a b} -> \partial_{a}{\delta{A_{b}}} - \partial_{b}{\delta{A_{a}}}, \lambda -> \delta{\lambda} ); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= - \frac{1}{2}\, ((\partial_{a}{\delta{A_{b}}} - \partial_{b}{\delta{A_{a}}}) f_{a b}) - \frac{1}{2}\, \bar{\delta{\lambda}} \gamma_{a} \partial_{a}{\lambda} - \frac{1}{2}\, \bar{\lambda} \gamma_{a} \partial_{a}{\delta{\lambda}}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @distribute!(%); @substitute!(%)( @(susy) ): @prodrule!(%): @distribute!(%): @unwrap!(%); @rewrite_diracbar!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= - \partial_{a}{\delta{A_{b}}} f_{a b} - \frac{1}{2}\, \bar{\delta{\lambda}} \gamma_{a} \partial_{a}{\lambda} - \frac{1}{2}\, \bar{\lambda} \gamma_{a} \partial_{a}{\delta{\lambda}}; \end{dmath*} \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} + \frac{1}{4}\, \bar{\gamma_{a b} \epsilon} \gamma_{c} \partial_{c}{\lambda} f_{a b} + \frac{1}{4}\, \bar{\lambda} \gamma_{a} \gamma_{b c} \epsilon \partial_{a}{f_{b c}}; \end{dmath*} \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} - \frac{1}{4}\, \bar{\epsilon} \gamma_{a b} \gamma_{c} \partial_{c}{\lambda} f_{a b} + \frac{1}{4}\, \bar{\lambda} \gamma_{a} \gamma_{b c} \epsilon \partial_{a}{f_{b c}}; \end{dmath*} \begin{verbatim} Warning: assuming Minkowski signature. \end{verbatim} {\color[named]{Blue}\begin{verbatim} @substitute!(%)( \partial_{c}{f_{a b}} -> \ppartial_{c}{f_{a b}} ): @pintegrate!(%){\ppartial}: @rename!(%){"\ppartial"}{"\partial"}: @prodrule!(%): @unwrap!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} - \frac{1}{4}\, \bar{\epsilon} \gamma_{a b} \gamma_{c} \partial_{c}{\lambda} f_{a b} - \frac{1}{4}\, \partial_{a}{\bar{\lambda}} \gamma_{a} \gamma_{b c} \epsilon f_{b c}; \end{dmath*} {\color[named]{Blue}\begin{verbatim} @join!(%){expand}: @distribute!(%): @eliminate_kr!(%): @substitute!(%)( \partial_{a}{\bar{\lambda}} -> \bar{\partial_{a}{\lambda}} ); @spinorsort!(%); \end{verbatim}} \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= \frac{1}{2}\, \bar{\epsilon} \gamma_{a} \partial_{b}{\lambda} f_{a b} - \frac{1}{4}\, \bar{\epsilon} \gamma_{a b c} \partial_{a}{\lambda} f_{b c} - \frac{1}{4}\, \bar{\partial_{a}{\lambda}} \gamma_{a b c} \epsilon f_{b c} - \frac{1}{2}\, \bar{\partial_{a}{\lambda}} \gamma_{b} \epsilon f_{a b}; \end{dmath*} \begin{dmath*}[compact, spread=2pt] S\specialcolon{}= (\frac{-1}{2})\, \bar{\epsilon} \gamma_{a b c} \partial_{a}{\lambda} f_{b c}; \end{dmath*} \end{document} cadabra-1.39/gui/widgets.cc000066400000000000000000000511071234107666300156000ustar00rootroot00000000000000/* Cadabra: a field-theory motivated computer algebra system. Copyright (C) 2001-2011 Kasper Peeters 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 3 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, see . */ #include "widgets.hh" #include #include #include #include #include #include #include #include #include #include //#define DEBUG 1 // General tool to strip spaces from both ends std::string trim(const std::string& s) { if(s.length() == 0) return s; int b = s.find_first_not_of(" \t\n"); int e = s.find_last_not_of(" \t\n"); if(b == -1) // No non-spaces return ""; return std::string(s, b, e - b + 1); } double TeXEngine::millimeter_per_inch = 25.4; TeXBuffer::TeXBuffer(Glib::RefPtr tb, TeXEngine& engine) : tex_source(tb), tex_request(0), engine_(engine) { } TeXBuffer::~TeXBuffer() { if(tex_request) engine_.checkout(tex_request); } void TeXBuffer::generate(const std::string& startwrap, const std::string& endwrap) { tex_request = engine_.checkin(tex_source->get_text(), startwrap, endwrap); } void TeXBuffer::regenerate() { assert(tex_request); engine_.modify(tex_request, tex_source->get_text()); } TeXEngine::TeXException::TeXException(const std::string& str) : std::logic_error(str) { } Glib::RefPtr TeXEngine::get_pixbuf(TeXEngine::TeXRequest *req) { if(req==0) // return empty pixbuf return Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, false, 8, 1, 1); if(req->needs_generating) convert_one(req); return req->pixbuf; } void TeXEngine::erase_file(const std::string& nm) const { unlink(nm.c_str()); } std::string TeXEngine::handle_latex_errors(const std::string& result) const { std::string::size_type pos=result.find("! LaTeX Error"); if(pos != std::string::npos) { return "LaTeX error, probably a missing style file. See the output below.\n\n" +result; } pos=result.find("! TeX capacity exceeded"); if(pos != std::string::npos) { return "Output cell too large (TeX capacity exceeded), output suppressed."; } pos=result.find("! Double superscript."); if(pos != std::string::npos) { return "Internal typesetting error: double superscript. Please report a bug.\n\n" + result; } pos=result.find("! Double subscript."); if(pos != std::string::npos) { return "Internal typesetting error: double subscript. Please report a bug.\n\n" + result; } pos=result.find("! Package breqn Error: "); if(pos != std::string::npos) { return "Typesetting error (breqn.sty related). Please report a bug.\n\n" + result; } pos=result.find("! Undefined control sequence"); if(pos != std::string::npos) { std::string::size_type undefpos=result.find("\n", pos+30); if(undefpos==std::string::npos) return "Undefined control sequence (failed to parse LaTeX output)."; std::string::size_type backslashpos=result.rfind("\\", undefpos); if(backslashpos==std::string::npos || backslashpos < 2) return "Undefined control sequence (failed to parse LaTeX output)."; std::string undefd=result.substr(backslashpos-1,undefpos-pos-30); return "Undefined control sequence:\n\n" +undefd+"\nNote that all symbols which you use in cadabra have to be valid LaTeX expressions. If they are not, you can still use the LaTeXForm property to make them print correctly; see the manual for more information."; } return ""; } TeXEngine::~TeXEngine() { // Delete all requests. std::set::iterator it=requests.begin(); while(it!=requests.end()) { delete (*it); ++it; } } TeXEngine::TeXEngine() : horizontal_pixels_(800), font_size_(12) { } void TeXEngine::set_geometry(int horpix) { if(horizontal_pixels_!=horpix) { // flag all requests as requiring an update std::set::iterator reqit=requests.begin(); while(reqit!=requests.end()) { (*reqit)->needs_generating=true; ++reqit; } } horizontal_pixels_=horpix; } void TeXEngine::set_font_size(int fontsize) { if(font_size_!=fontsize) { // flag all requests as requiring an update std::set::iterator reqit=requests.begin(); while(reqit!=requests.end()) { (*reqit)->needs_generating=true; ++reqit; } } font_size_=fontsize; } TeXEngine::TeXRequest::TeXRequest() : needs_generating(true) { } TeXEngine::TeXRequest *TeXEngine::checkin(const std::string& txt, const std::string& startwrap, const std::string& endwrap) { TeXRequest *req = new TeXRequest; req->latex_string=txt; req->start_wrap=startwrap; req->end_wrap=endwrap; req->needs_generating=true; requests.insert(req); return req; } void TeXEngine::checkout(TeXRequest *req) { std::set::iterator it=requests.find(req); assert(it!=requests.end()); requests.erase(it); } TeXEngine::TeXRequest *TeXEngine::modify(TeXRequest *req, const std::string& txt) { req->latex_string=txt; req->needs_generating=true; return req; } void TeXEngine::convert_all() { if(requests.size()!=0) convert_set(requests); } void TeXEngine::convert_one(TeXRequest *req) { std::set reqset; reqset.insert(req); convert_set(reqset); } void TeXEngine::convert_set(std::set& reqs) { // We now follow // // https://www.securecoding.cert.org/confluence/display/seccode/FI039-C.+Create+temporary+files+securely // // for temporary files. char olddir[1024]; if(getcwd(olddir, 1023)==NULL) olddir[0]=0; if(chdir("/tmp")==-1) throw TeXException("Failed to chdir to /tmp."); char templ[]="/tmp/cdbXXXXXX"; // The size in mm or inches which we use will in the end determine how large // the font will come out. // // For given horizontal size, we stretch this up to the full window // width using horizontal_pixels/(horizontal_size/millimeter_per_inch) dots per inch. // The appropriate horizontal size in mm is determined by trial and error, // and of course scales with the number of horizontal pixels. const double horizontal_mm=horizontal_pixels_*(12.0/font_size_)/3.94; //#ifdef DEBUG // std::cerr << "tex_it: font_size " << font_size << std::endl // << " pixels " << horizontal_pixels_ << std::endl // << " mm " << horizontal_mm << std::endl; //#endif //(int)(millimeter_per_inch*horizontal_pixels/100.0); //140; const double vertical_mm=10*horizontal_mm; // Write each string in the set of requests into a buffer, separating // them by a page eject. std::ostringstream total; int fd = mkstemp(templ); if(fd == -1) throw TeXException("Failed to create temporary file in /tmp."); total << "\\documentclass[12pt]{article}\n" << "\\usepackage[dvips,verbose,voffset=0pt,hoffset=0pt,textwidth=" << horizontal_mm << "mm,textheight=" << vertical_mm << "mm]{geometry}\n" << "\\usepackage{color}\\usepackage{amssymb}\n" << "\\usepackage[parfill]{parskip}\n\\usepackage{tableaux}\n"; for(size_t i=0; i::iterator reqit=reqs.begin(); while(reqit!=reqs.end()) { if((*reqit)->needs_generating) { if((*reqit)->latex_string.size()>100000) total << "Expression too long, output suppressed.\n"; else { if((*reqit)->start_wrap.size()>0) total << (*reqit)->start_wrap; total << (*reqit)->latex_string; if((*reqit)->end_wrap.size()>0) total << "\n" << (*reqit)->end_wrap; else total << "\n"; } total << "\\eject\n"; } ++reqit; } total << "\\end{document}\n"; // Now write the 'total' buffer to the .tex file ssize_t start=0; do { ssize_t written=write(fd, &(total.str().c_str()[start]), total.str().size()-start); if(written>=0) start+=written; else { if(errno != EINTR) { close(fd); throw TeXException("Failed to write LaTeX temporary file."); } } } while(start(total.str().size())); close(fd); #ifdef DEBUG std::cerr << templ << std::endl; std::cerr << "---\n" << total.str() << "\n---" << std::endl; #endif std::string nf=std::string(templ)+".tex"; rename(templ, nf.c_str()); #ifdef __CYGWIN__ // MikTeX does not see /tmp, it needs \cygwin\tmp nf="\\cygwin"+nf; pcrecpp::RE("/").GlobalReplace("\\\\", &nf); #endif // Run LaTeX on the .tex file. modglue::child_process latex_proc("latex"); latex_proc << "--interaction" << "nonstopmode" << nf; std::string result; try { latex_proc.call("", result); erase_file(std::string(templ)+".tex"); erase_file(std::string(templ)+".aux"); erase_file(std::string(templ)+".log"); #ifdef DEBUG std::cerr << result << std::endl; #endif std::string err=handle_latex_errors(result); if(err.size()>0) { reqit=reqs.begin(); while(reqit!=reqs.end()) (*reqit++)->needs_generating=false; erase_file(std::string(templ)+".dvi"); if(chdir(olddir)==-1) throw TeXException(err+" (and cannot chdir back to original "+olddir+")"); throw TeXException(err); } } catch(std::logic_error& err) { erase_file(std::string(templ)+".tex"); erase_file(std::string(templ)+".dvi"); erase_file(std::string(templ)+".aux"); erase_file(std::string(templ)+".log"); std::string latex_err=handle_latex_errors(result); reqit=reqs.begin(); while(reqit!=reqs.end()) (*reqit++)->needs_generating=false; if(latex_err.size()>0) { if(chdir(olddir)==-1) throw TeXException(latex_err+" (and cannot chdir back to original "+olddir+")"); throw TeXException(latex_err); } // Even if we cannot find an explicit error in the output, we have to terminate // since LaTeX has thrown an exception. if(chdir(olddir)==-1) throw TeXException("Cannot start LaTeX, is it installed? (and cannot chdir back to original)"); throw TeXException("Cannot start LaTeX, is it installed?"); } // Convert the entire dvi file to png files. // modglue::child_process dvipng_proc("dvipng"); std::ostringstream rgbspec, resspec; dvipng_proc << "-T" << "tight" << "-bg" << "Transparent"; // << "-fg"; // rgbspec << "\"rgb " // << foreground_colour.get_red()/65536.0 << " " // << foreground_colour.get_green()/65536.0 << " " // << foreground_colour.get_blue()/65536.0 << "\""; // dvipng_proc << rgbspec.str(); dvipng_proc << "-D"; resspec << horizontal_pixels_/(1.0*horizontal_mm)*millimeter_per_inch; dvipng_proc << resspec.str() << std::string(templ)+".dvi"; try { dvipng_proc.call("", result); #ifdef DEBUG std::cerr << result << std::endl; #endif } catch(std::logic_error& ex) { // Erase all dvi and png files and put empty pixbufs into the TeXRequests. erase_file(std::string(templ)+".dvi"); reqit=reqs.begin(); int pagenum=1; while(reqit!=reqs.end()) { if((*reqit)->needs_generating) { std::ostringstream pngname; pngname << std::string(templ) << pagenum << ".png"; erase_file(pngname.str()); (*reqit)->pixbuf = Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, false, 8, 1, 1); (*reqit)->needs_generating=true; ++pagenum; } ++reqit; } if(chdir(olddir)==-1) throw TeXException( std::string("Cannot run dvipng, is it installed? (and cannot chdir back to original)\n\n")+ex.what()); throw TeXException(std::string("Cannot run dvipng, is it installed?\n\n")+ex.what()); } erase_file(std::string(templ)+".dvi"); // Conversion completed successfully, now convert all resulting PNG files to Pixbuf images. reqit=reqs.begin(); int pagenum=1; while(reqit!=reqs.end()) { if((*reqit)->needs_generating) { std::ostringstream pngname; pngname << std::string(templ) << pagenum << ".png"; std::ifstream tst(pngname.str().c_str()); if(tst.good()) { (*reqit)->pixbuf = Gdk::Pixbuf::create_from_file(pngname.str()); (*reqit)->needs_generating=false; erase_file(pngname.str()); } ++pagenum; } ++reqit; } if(chdir(olddir)==-1) throw TeXException("Failed to chdir back to " +std::string(olddir)+"."); } TeXView::TeXView(Glib::RefPtr texb, int hmargin) : texbuf(texb), vbox(false, 10), hbox(false, hmargin) { add(vbox); vbox.pack_start(hbox, Gtk::PACK_SHRINK, 0); hbox.pack_start(image, Gtk::PACK_SHRINK, hmargin); // set_state(Gtk::STATE_PRELIGHT); modify_bg(Gtk::STATE_NORMAL, Gdk::Color("white")); } void TeXView::on_show() { image.set(texbuf->get_pixbuf()); Gtk::EventBox::on_show(); } void TeXView::update_image() { image.set(texbuf->get_pixbuf()); } ExpressionInput::exp_input_tv::exp_input_tv(Glib::RefPtr tb) : Gtk::TextView(tb) { // get_buffer()->signal_insert().connect(sigc::mem_fun(this, &exp_input_tv::on_my_insert), false); // get_buffer()->signal_erase().connect(sigc::mem_fun(this, &exp_input_tv::on_my_erase), false); } ExpressionInput::ExpressionInput(Glib::RefPtr tb, const std::string& fontname, int hmargin) : edit(tb) { // scroll_.set_size_request(-1,200); // scroll_.set_border_width(1); // scroll_.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS); edit.modify_font(Pango::FontDescription(fontname)); edit.set_wrap_mode(Gtk::WRAP_NONE); edit.modify_text(Gtk::STATE_NORMAL, Gdk::Color("blue")); edit.set_pixels_above_lines(LINE_SPACING); edit.set_pixels_below_lines(LINE_SPACING); edit.set_pixels_inside_wrap(2*LINE_SPACING); edit.set_left_margin(hmargin); edit.set_accepts_tab(false); edit.signal_button_press_event().connect(sigc::mem_fun(this, &ExpressionInput::handle_button_press), false); // edit.get_buffer()->signal_changed().connect(sigc::mem_fun(this, &ExpressionInput::handle_changed)); // add(hbox); // hbox.add(vsep); // hbox.add(edit); add(edit); // set_border_width(3); } bool ExpressionInput::exp_input_tv::on_key_press_event(GdkEventKey* event) { // std::cerr << event->keyval << ", " << event->state << " pressed" << std::endl; if(get_editable() && event->keyval==GDK_Return && (event->state&Gdk::SHIFT_MASK)) {// shift-return Glib::RefPtr textbuf=get_buffer(); std::string tmp(trim(textbuf->get_text(get_buffer()->begin(), get_buffer()->end()))); // Determine whether this is a valid input cell: should end either on a delimiter or // on a delimeter-space-quoted-file-name combination. bool is_ok=false; if(tmp.size()>0) { if(tmp[0]!='#' && tmp[tmp.size()-1]!=';' && tmp[tmp.size()-1]!=':' && tmp[tmp.size()-1]!='.' && tmp[tmp.size()-1]!='\"') { is_ok=false; } else is_ok=true; } if(!is_ok) { Gtk::MessageDialog md("Input error"); md.set_secondary_text("This cell does not end with a delimiter (a \":\", \";\" or \".\")"); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); md.run(); } else { #ifdef DEBUG std::cerr << "sending: " << tmp << std::endl; #endif content_changed(); emitter(tmp); } return true; } else { bool retval=Gtk::TextView::on_key_press_event(event); while (gtk_events_pending ()) gtk_main_iteration (); // If this was a real key press (i.e. not just SHIFT or ALT or similar), emit a // signal so that the cell can be scrolled into view if necessary. // FIXME: I do not know how to do this correctly, check docs. if(event->keyval < 65000L) content_changed(); return retval; } } bool ExpressionInput::handle_button_press(GdkEventButton* button) { if(button->button!=2) return false; Glib::RefPtr refClipboard = Gtk::Clipboard::get(GDK_SELECTION_PRIMARY); std::vector sah=refClipboard->wait_for_targets(); bool hastext=false; bool hasstring=false; Gtk::SelectionData sd; // find out _where_ to insert Gtk::TextBuffer::iterator insertpos; int somenumber; edit.get_iter_at_position(insertpos, somenumber, button->x, button->y); ++insertpos; for(unsigned int i=0; iwait_for_contents("cadabra"); std::string topaste=sd.get_data_as_string(); insertpos=edit.get_buffer()->insert(insertpos, topaste); edit.get_buffer()->place_cursor(insertpos); return true; } else if(sah[i]=="TEXT") hastext=true; else if(sah[i]=="STRING") hasstring=true; } if(hastext) sd=refClipboard->wait_for_contents("TEXT"); else if(hasstring) sd=refClipboard->wait_for_contents("STRING"); if(hastext || hasstring) { insertpos=edit.get_buffer()->insert(insertpos, sd.get_data_as_string()); edit.get_buffer()->place_cursor(insertpos); } return true; } bool ExpressionInput::exp_input_tv::on_expose_event(GdkEventExpose *event) { Glib::RefPtr win = Gtk::TextView::get_window(Gtk::TEXT_WINDOW_TEXT); bool ret=Gtk::TextView::on_expose_event(event); int w, h, x, y, d; win->get_geometry(x,y,w,h,d); // std::cout << w << ", " << h << std::endl; Cairo::RefPtr cr = win->create_cairo_context(); // if(event) { // // clip to the area that needs to be re-exposed so we don't draw any // // more than we need to. // std::cout << event->area.width << " x " << event->area.height << std::endl; // cr->rectangle(event->area.x, event->area.y, // event->area.width, event->area.height); // cr->clip(); // } // paint the background cr->set_source_rgba(1.0, 1.0, 1.0, 1.0); cr->rectangle(5,3,8,h-3); cr->fill(); cr->set_source_rgba(.2, .2, .7, 1.0); cr->set_line_width(1.0); cr->set_antialias(Cairo::ANTIALIAS_NONE); cr->move_to(8,3); cr->line_to(5,3); cr->line_to(5,h-3); cr->line_to(8,h-3); cr->stroke(); return ret; } // gdouble page_inc, step_inc, upper, lower, pos; // // GtkAdjustment* vadj = gtk_scrolled_window_get_vadjustment( // GTK_SCROLLED_WINDOW(scrolled_window)); // // page_inc = vadj->page_increment; // step_inc = vadj->step_increment; // lower = vadj->lower; // // /* Otherwise we sometimes scroll down into a page of black. */ // upper = vadj->upper - page_inc - step_inc; // // /* Center on the widget. */ // pos = (gdouble)widget->allocation.y - page_inc/2; // // gtk_adjustment_set_value(vadj, CLAMP(pos, lower, upper)); // TeXInput::exp_input_tv::exp_input_tv(Glib::RefPtr tb) : Gtk::TextView(tb), is_modified(false), folded_away(false) { } TeXInput::TeXInput(Glib::RefPtr tb, Glib::RefPtr texb, const std::string& fontname) : edit(tb), texview(texb, 10) { // scroll_.set_size_request(-1,200); // scroll_.set_border_width(1); // scroll_.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS); edit.modify_font(Pango::FontDescription(fontname)); edit.set_wrap_mode(Gtk::WRAP_WORD); edit.modify_text(Gtk::STATE_NORMAL, Gdk::Color("darkgray")); edit.set_pixels_above_lines(LINE_SPACING); edit.set_pixels_below_lines(LINE_SPACING); edit.set_pixels_inside_wrap(2*LINE_SPACING); edit.set_left_margin(10); set_spacing(10); // add(expander); // expander.set_label_widget(texview); // expander.add(edit); // expander.set_expanded(); pack_start(edit); pack_start(texview); } bool TeXInput::is_folded() const { return edit.folded_away; } void TeXInput::set_folded(bool onoff) { if(edit.folded_away==onoff) return; edit.folded_away=onoff; if(edit.folded_away) remove(edit); else { pack_start(edit); reorder_child(edit, 0); edit.show(); } } bool TeXInput::exp_input_tv::on_key_press_event(GdkEventKey* event) { if(get_editable() && event->keyval==GDK_Return && (event->state&Gdk::SHIFT_MASK)) {// shift-return // std::cerr << "activate!!" << std::endl; Glib::RefPtr textbuf=get_buffer(); // std::cerr << textbuf->get_text(textbuf->get_start_iter(), textbuf->get_end_iter()) << std::endl; std::string tmp(textbuf->get_text(get_buffer()->begin(), get_buffer()->end())); #ifdef DEBUG std::cerr << "running: " << tmp << std::endl; #endif emitter(tmp); is_modified=false; // set_editable(false); // textbuf->set_text(""); return true; } else { is_modified=true; bool retval=Gtk::TextView::on_key_press_event(event); return retval; } } Glib::RefPtr TeXBuffer::create(Glib::RefPtr tb, TeXEngine& engine) { return Glib::RefPtr(new TeXBuffer(tb, engine) ); } Glib::RefPtr TeXBuffer::get_pixbuf() { return engine_.get_pixbuf(tex_request); } cadabra-1.39/gui/widgets.hh000066400000000000000000000132141234107666300156070ustar00rootroot00000000000000/* Cadabra: a field-theory motivated computer algebra system. Copyright (C) 2001-2011 Kasper Peeters 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 3 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, see . */ #ifndef widgets_hh__ #define widgets_hh__ #include #include #include #include #include #include #include #include #include #include #include const int LINE_SPACING=3; #include "../src/stopwatch.hh" std::string trim(const std::string& s); /// TeXEngine is a singleton which is used to convert LaTeX strings /// into Gdk::Pixbuf objects. This is a two-stage process: you first /// 'check in' a string into the system, in exchange for a pointer to /// a TeXRequest object. When you are ready to retrieve the image, /// call 'get_pixbuf'. /// /// If you need to generate images for more than one string, simply /// check them all in and then call 'convert_all' before retrieving /// the pixbufs. class TeXEngine { public: class TeXException : public std::logic_error { public: TeXException(const std::string&); }; class TeXRequest { public: TeXRequest(); friend class TeXEngine; private: std::string latex_string; std::string start_wrap, end_wrap; bool needs_generating; Glib::RefPtr pixbuf; }; TeXEngine(); ~TeXEngine(); /// Set the width and font size for all images to be generated. void set_geometry(int horizontal_pixels); void set_font_size(int font_size); std::vector latex_packages; /// All checkin/checkout conversion routines. TeXRequest *checkin(const std::string&, const std::string& startwrap, const std::string& endwrap); TeXRequest *modify(TeXRequest *, const std::string&); Glib::RefPtr get_pixbuf(TeXRequest *); void convert_all(); void checkout(TeXRequest *); private: static double millimeter_per_inch; std::set requests; int horizontal_pixels_; int font_size_; void erase_file(const std::string&) const; void convert_one(TeXRequest*); void convert_set(std::set&); std::string handle_latex_errors(const std::string&) const; }; /// TeXBuffer is like a TextBuffer, but now for images /// generated by TeX+dvipng. That is, for each cell in the /// document, there is one TeXBuffer (and one TextBuffer); /// the TeXView and TextView classes use these buffers to /// get their content. class TeXBuffer : public Glib::Object { public: TeXBuffer(Glib::RefPtr, TeXEngine&); ~TeXBuffer(); void generate(const std::string& startwrap, const std::string& endwrap); void regenerate(); static Glib::RefPtr create(Glib::RefPtr, TeXEngine&); Glib::RefPtr get_pixbuf(); Glib::RefPtr tex_source; TeXEngine::TeXRequest *tex_request; protected: TeXEngine &engine_; }; /// TeXView is an image widget with some additional Gtk /// structure; we use it to display images generated by TeX. /// The actual pixbuf is generated by a TeXBuffer, which in /// turn uses a TeXEngine. class TeXView : public Gtk::EventBox { public: TeXView(Glib::RefPtr, int hmargin=25); Glib::RefPtr texbuf; Gtk::VBox vbox; Gtk::HBox hbox; Gtk::Image image; void update_image(); protected: virtual void on_show(); }; /// ExpressionInput is essentially a TextView with some /// additional i/o logic. class ExpressionInput : public Gtk::VBox { public: ExpressionInput(Glib::RefPtr, const std::string& fontname, int hmargin=25); class exp_input_tv : public Gtk::TextView { public: exp_input_tv(Glib::RefPtr); virtual bool on_key_press_event(GdkEventKey*); virtual bool on_expose_event(GdkEventExpose* event); sigc::signal1 emitter; sigc::signal0 content_changed; }; bool handle_button_press(GdkEventButton *); exp_input_tv edit; Gtk::HBox hbox; Gtk::VSeparator vsep; }; /// TeXInput is a widget which can be used to edit and display /// TeX input. Double-clicking on the graphical TeX version /// toggles visibility of the edit box. class TeXInput : public Gtk::VBox { public: TeXInput(Glib::RefPtr, Glib::RefPtr, const std::string& fontname); class exp_input_tv : public Gtk::TextView { public: exp_input_tv(Glib::RefPtr); virtual bool on_key_press_event(GdkEventKey*); sigc::signal1 emitter; bool is_modified; friend class TeXInput; protected: bool folded_away; }; exp_input_tv edit; bool is_folded() const; void set_folded(bool); TeXView texview; }; extern class TeXEngine tex_engine_main, tex_engine_help; #endif cadabra-1.39/gui/window.cc000066400000000000000000003023071234107666300154420ustar00rootroot00000000000000/* Cadabra: a field-theory motivated computer algebra system. Copyright (C) 2001-2011 Kasper Peeters 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 3 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, see . */ // #define DEBUG 1 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../src/config.h" #include "window.hh" TeXEngine tex_engine_main, tex_engine_help; #define THEFONT "cmtt12" const char * const XCadabra::autocomplete_strings[] = { "\\alpha", "\\beta", "\\gamma", "\\delta", "\\epsilon", "\\zeta", "\\eta", "\\theta", "\\iota", "\\kappa", "\\lambda", "\\mu", "\\nu", "\\xi", "\\omicron", "\\pi", "\\rho", "\\sigma", "\\tau", "\\upsilon", "\\phi", "\\chi", "\\psi", "\\omega", "\\Alpha", "\\Beta", "\\Gamma", "\\Delta", "\\Epsilon", "\\Zeta", "\\Eta", "\\Theta", "\\Iota", "\\Kappa", "\\Lambda", "\\Mu", "\\Nu", "\\Xi", "\\Omicron", "\\Pi", "\\Rho", "\\Sigma", "\\Tau", "\\Upsilon", "\\Phi", "\\Chi", "\\Psi", "\\Omega", "\\partial", "\\infty", "\\dot", "\\commutator", "\\anticommutator" }; //PropertyList::PropertyList() // { // set_size_request(200,900); // pack_start(scroll, true, true); // scroll.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS); // scroll.set_border_width(1); // tv.set_editable(false); // tv.set_wrap_mode(Gtk::WRAP_WORD); // textbuf=tv.get_buffer(); // scroll.add(tv); // show_all(); // } ActionBase::ActionBase(Glib::RefPtr cl) : cell(cl) { } ActionAddText::ActionAddText(Glib::RefPtr dc_, int pos_, const std::string& str) : ActionBase(dc_), insert_pos(pos_), text(str) { } void ActionAddText::execute(XCadabra&) { // This only get called when doing a 'redo'. It is not called // directly as a consequence of any other user action: // ActionAddText objects get created only _after_ a user has added // text to a TextBuffer, so the action has already happened. Glib::RefPtr buf; if(cell->cell_type == DataCell::c_input) buf = cell->textbuf; else buf = cell->texbuf->tex_source; Gtk::TextIter start=buf->begin(); for(int i=0; iinsert(start, text); } void ActionAddText::revert(XCadabra&) { Glib::RefPtr buf; if(cell->cell_type == DataCell::c_input) buf = cell->textbuf; else buf = cell->texbuf->tex_source; Gtk::TextIter start=buf->begin(); for(int i=0; ierase(start, end); } ActionRemoveText::ActionRemoveText(Glib::RefPtr dc_, int fr_, int to_, const std::string& str) : ActionBase(dc_), from_pos(fr_), to_pos(to_), removed_text(str) { } void ActionRemoveText::execute(XCadabra&) { // This only get called when doing a 'redo'. It is not called // directly as a consequence of any other user action: // ActionRemoveText objects get created only _after_ a user has added // text to a TextBuffer, so the action has already happened. Glib::RefPtr buf; if(cell->cell_type == DataCell::c_input) buf = cell->textbuf; else buf = cell->texbuf->tex_source; Gtk::TextIter start=buf->begin(); for(int i=0; ierase(start, end); } void ActionRemoveText::revert(XCadabra&) { Glib::RefPtr buf; if(cell->cell_type == DataCell::c_input) buf = cell->textbuf; else buf = cell->texbuf->tex_source; Gtk::TextIter start=buf->begin(); for(int i=0; iinsert(start, removed_text); } ActionAddCell::ActionAddCell(Glib::RefPtr toadd, Glib::RefPtr ref_, bool before_) : ActionBase(toadd), ref(ref_), before(before_) { } void ActionAddCell::execute(XCadabra& xc) { xc.add_cell(cell, ref, before); xc.show_cell(cell); xc.active_canvas->cell_grab_focus(cell); // Then insert the associated cells, if there are any if(associated_cells.size()>0) { Glib::RefPtr previous_cell=cell; for(size_t i=0; iremove_cell(*fnd); if(*fnd != cell) associated_cells.push_back(*fnd); fnd=xc.datacells.erase(fnd); if(fnd==xc.datacells.end() || (*fnd)->cell_type==DataCell::c_input || (*fnd)->cell_type==DataCell::c_tex) break; } // We have to put the cursor in the previous input cell or in the previous open TeX cell. // So walk up the cells until we meet this condition. while((*prevcell)->cell_type!=DataCell::c_input && !( (*prevcell)->cell_type==DataCell::c_tex && (*prevcell)->tex_hidden==false) ) --prevcell; xc.active_canvas->cell_grab_focus(*prevcell); } ActionRemoveCell::ActionRemoveCell(Glib::RefPtr toremove) : ActionBase(toremove) { } ActionRemoveCell::~ActionRemoveCell() { } void ActionRemoveCell::execute(XCadabra& xc) { xc.selected=0; XCadabra::DataCells_t::iterator fnd=std::find(xc.datacells.begin(), xc.datacells.end(), cell); assert(fnd!=xc.datacells.end()); assert(fnd!=xc.datacells.begin()); // Store a pointer to the previous DataCell. XCadabra::DataCells_t::iterator fnd_prev=fnd; --fnd_prev; prev_cell=(*fnd_prev); // Remove cells until an input or tex cell is found. associated_cells.clear(); while(fnd!=xc.datacells.end()) { for(unsigned int i=0; iremove_cell(*fnd); if(*fnd != cell) associated_cells.push_back(*fnd); fnd=xc.datacells.erase(fnd); if(fnd==xc.datacells.end() || (*fnd)->cell_type==DataCell::c_input || (*fnd)->cell_type==DataCell::c_tex) break; } // Position the cursor. if(fnd!=xc.datacells.end()) { // We have to put the cursor in the next input cell or in the next open TeX cell. // So walk down the cells until we meet this condition (or end). while(fnd!=xc.datacells.end() && (*fnd)->cell_type!=DataCell::c_input && !( (*fnd)->cell_type==DataCell::c_tex && (*fnd)->tex_hidden==false) ) ++fnd; if(fnd!=xc.datacells.end()) xc.active_canvas->cell_grab_focus(*fnd); } else { // There is no cell below (i.e. we just deleted the last cell). // Find the last input cell of the notebook and activate that one. // (i.e. we walk upward here, as opposed to the normal action, which is to // move one input cell down). --fnd; while(fnd!=xc.datacells.begin() && (*fnd)->cell_type!=DataCell::c_input && !( (*fnd)->cell_type==DataCell::c_tex && (*fnd)->tex_hidden==false) ) { --fnd; } xc.active_canvas->cell_grab_focus(*fnd); } } void ActionRemoveCell::revert(XCadabra& xc) { // Find prev_cell in the currently active cells. XCadabra::DataCells_t::iterator fnd=std::find(xc.datacells.begin(), xc.datacells.end(), prev_cell); assert(fnd!=xc.datacells.end()); // Re-insert the input cell back into the tree. xc.add_cell(cell, (*fnd), false); xc.show_cell(cell); // Then insert the associated cells. if(associated_cells.size()>0) { Glib::RefPtr previous_cell=cell; for(size_t i=0; icell_grab_focus(cell); } DataCell::DataCell(cell_t ct, const std::string& str, bool texhidden) : cell_type(ct), tex_hidden(texhidden), sensitive(true), sectioning(0), running(false) { textbuf=Gtk::TextBuffer::create(); textbuf->set_text(trim(str)); switch(cell_type) { case c_error: case c_output: case c_comment: case c_texcomment: case c_tex: texbuf=TeXBuffer::create(textbuf, tex_engine_main); break; case c_input: break; } } NotebookCanvas::NotebookCanvas(XCadabra& doc_) : doc(doc_) { pack1(scroll, true, true); scroll.set_policy(Gtk::POLICY_ALWAYS, Gtk::POLICY_ALWAYS); scroll.set_border_width(1); scroll.add(ebox); ebox.add(scrollbox); ebox.modify_bg(Gtk::STATE_NORMAL, Gdk::Color("white")); // scrollbox.pack_start(bottomline, Gtk::PACK_SHRINK); } NotebookCanvas::~NotebookCanvas() { } void NotebookCanvas::redraw_cells() { VisualCells_t::iterator it=visualcells.begin(); std::ostringstream fstr; fstr << THEFONT << " " << 12+(doc.font_step*2); while(it!=visualcells.end()) { switch((*it)->datacell->cell_type) { case DataCell::c_input: (*it)->inbox->edit.modify_font(Pango::FontDescription(fstr.str())); break; case DataCell::c_comment: case DataCell::c_texcomment: case DataCell::c_error: case DataCell::c_output: (*it)->outbox->update_image(); // (*it)->outbox->image.set((*it)->datacell->texbuf->get_pixbuf()); break; case DataCell::c_tex: (*it)->texbox->edit.modify_font(Pango::FontDescription(fstr.str())); (*it)->texbox->texview.update_image(); // (*it)->texbox->texview.image.set((*it)->datacell->texbuf->get_pixbuf()); break; } ++it; } } void NotebookCanvas::show_cell(Glib::RefPtr datacell) { VisualCells_t::iterator it=visualcells.begin(); while(it!=visualcells.end()) { if((*it)->datacell==datacell) { switch((*it)->datacell->cell_type) { case DataCell::c_input: (*it)->inbox->show_all(); break; case DataCell::c_comment: case DataCell::c_texcomment: case DataCell::c_error: case DataCell::c_output: (*it)->outbox->show_all(); break; case DataCell::c_tex: (*it)->texbox->show_all(); break; } } ++it; } } VisualCell *NotebookCanvas::add_cell(Glib::RefPtr dc, Glib::RefPtr ref, bool before) { VisualCell *newcell=new VisualCell; newcell->datacell=dc; // Temporarily remove bottom line marker. // scrollbox.remove(bottomline); // Find the correct place to insert the new cell in visualcells, and keep // track of the number so we can insert the widget at the right spot in the Gtk // container later. int cellnum=0; if(ref==0) visualcells.push_back(newcell); else { VisualCells_t::iterator it=visualcells.begin(); while(it!=visualcells.end()) { if((*it)->datacell==ref) { if(!before) { // skip to the next input cell; NOTE: this should skip in the same way // as the XCadabra::add_cell method! do { ++it; ++cellnum; } while(it!=visualcells.end() && ( /* (*it)->datacell->cell_type==DataCell::c_comment || */ (*it)->datacell->cell_type==DataCell::c_output || (*it)->datacell->cell_type==DataCell::c_error) ); } visualcells.insert(it, newcell); break; } ++it; ++cellnum; } } #ifdef DEBUG std::cerr << "gtk logic" << std::endl; #endif Gtk::VBox::BoxList bl=scrollbox.children(); Gtk::VBox::BoxList::iterator gtkit; if(ref==0) gtkit=bl.end(); else { gtkit=bl.begin(); while(cellnum!=0) { ++gtkit; --cellnum; } } // Insert the widget in the Gtk container and connect signals. #ifdef DEBUG std::cerr << "inserting" << std::endl; #endif switch(dc->cell_type) { case DataCell::c_input: { #ifdef DEBUG std::cerr << "incell" << std::endl; #endif std::ostringstream fstr; fstr << THEFONT << " " << 12+(doc.font_step*2); newcell->inbox=manage( new ExpressionInput(dc->textbuf, fstr.str()) ); // Gtk::VBox::BoxList::iterator newit= bl.insert(gtkit, *newcell->inbox); gtk_box_set_child_packing(((Gtk::Box *)(&scrollbox))->gobj(), ((Gtk::Widget *)(newcell->inbox))->gobj(), false, false, 10, GTK_PACK_START); // while (gtk_events_pending ()) // gtk_main_iteration (); // Connect to signal for 'ctrl-enter pressed', i.e. 'feed this cell to the kernel'. newcell->inbox->edit.emitter.connect( sigc::bind( sigc::mem_fun(doc, &XCadabra::handle_editbox_output), this, newcell)); // Connect signals such that we can grab focus and scroll the widget into view when necessary. newcell->inbox->edit.signal_grab_focus().connect( sigc::bind( sigc::mem_fun(doc, &XCadabra::handle_on_grab_focus), this, newcell)); newcell->inbox->edit.content_changed.connect( sigc::bind( sigc::mem_fun(this, &NotebookCanvas::scroll_into_view_callback), newcell)); break; } case DataCell::c_error: case DataCell::c_output: case DataCell::c_texcomment: case DataCell::c_comment: { newcell->outbox=manage( new TeXView(dc->texbuf) ); // Gtk::VBox::BoxList::iterator newit= bl.insert(gtkit, *newcell->outbox); // REPORT BUG: this sometimes segfaults // (*newit).set_options(Gtk::PACK_SHRINK); gtk_box_set_child_packing(((Gtk::Box *)(&scrollbox))->gobj(), ((Gtk::Widget *)(newcell->outbox))->gobj(), false, false, (dc->cell_type==DataCell::c_texcomment?3:10), GTK_PACK_START); newcell->outbox->signal_button_release_event().connect( sigc::bind( sigc::mem_fun(doc, &XCadabra::handle_outbox_select), this, newcell)); break; } case DataCell::c_tex: { std::ostringstream fstr; fstr << THEFONT << " " << 12+(doc.font_step*2); newcell->texbox=manage( new TeXInput(dc->textbuf, dc->texbuf, fstr.str()) ); newcell->texbox->texview.signal_button_release_event().connect( sigc::bind( sigc::mem_fun(doc, &XCadabra::handle_visibility_toggle), this, newcell)); // Connect signal requesting update of the TeX rendering. newcell->texbox->edit.emitter.connect( sigc::bind( sigc::mem_fun(doc, &XCadabra::handle_tex_update_request), this, newcell)); // Gtk::VBox::BoxList::iterator newit= bl.insert(gtkit, *newcell->texbox); gtk_box_set_child_packing(((Gtk::Box *)(&scrollbox))->gobj(), ((Gtk::Widget *)(newcell->texbox))->gobj(), false, false, 10, GTK_PACK_START); // REPORT BUG: this sometimes segfaults // (*newit).set_options(Gtk::PACK_SHRINK); newcell->texbox->edit.signal_grab_focus().connect( sigc::bind( sigc::mem_fun(doc, &XCadabra::handle_on_grab_focus), this, newcell)); // Hide source depending on setting in the datacell. newcell->texbox->set_folded(newcell->datacell->tex_hidden); break; } } // Restore bottom line marker // scrollbox.pack_start(bottomline, Gtk::PACK_SHRINK); // bottomline.show(); return newcell; //visualcells.back(); } void NotebookCanvas::remove_cell(Glib::RefPtr dc) { int cellnum=0; VisualCells_t::iterator it=visualcells.begin(); while(it!=visualcells.end()) { if((*it)->datacell==dc) break; ++it; ++cellnum; } assert(it!=visualcells.end()); switch((*it)->datacell->cell_type) { case DataCell::c_input: scrollbox.remove(*((*it)->inbox)); break; case DataCell::c_error: case DataCell::c_comment: case DataCell::c_texcomment: case DataCell::c_output: scrollbox.remove(*((*it)->outbox)); break; case DataCell::c_tex: scrollbox.remove(*((*it)->texbox)); break; } // delete (*it); // free the memory associated to the VisualCell TRACK visualcells.erase(it); } void NotebookCanvas::cell_grab_focus(Glib::RefPtr dc) { VisualCells_t::iterator it=visualcells.begin(); while(it!=visualcells.end()) { if((*it)->datacell==dc) { cell_grab_focus(*it); break; } ++it; } } void NotebookCanvas::cell_grab_focus(VisualCell *vis) { VisualCells_t::iterator it=std::find(visualcells.begin(), visualcells.end(), vis); if(it!=visualcells.end()) { switch(vis->datacell->cell_type) { case DataCell::c_input: { vis->inbox->edit.grab_focus(); // we should not scroll here, because scrolling may already // have occurred during the grab_focus of the gtk cell above. break; } case DataCell::c_error: case DataCell::c_output: case DataCell::c_comment: case DataCell::c_texcomment: break; case DataCell::c_tex: if(vis->datacell->tex_hidden==false) { vis->texbox->edit.grab_focus(); // we should not scroll here, because scrolling may already // have occurred during the grab_focus of the gtk cell above. } break; } } } //void NotebookCanvas::scroll_to(Gtk::Allocation al) // { // Gtk::Adjustment *va=scroll.get_vadjustment(); // if(al.get_y()+al.get_height() < va->get_value() || // al.get_y()+al.get_height() > va->get_value() + va->get_page_size()) { // va->set_value(std::max(0.0, // std::min((double)(al.get_y()-va->get_page_size()+al.get_height()+40), // va->get_upper()-va->get_page_size()))); // } // } bool NotebookCanvas::scroll_into_view(Glib::RefPtr dc, bool center) { VisualCells_t::iterator it=visualcells.begin(); while(it!=visualcells.end()) { if((*it)->datacell==dc) { return scroll_into_view(*it, center); } ++it; } return false; } bool NotebookCanvas::scroll_into_view_callback(VisualCell *vc) { return scroll_into_view(vc, false); } bool NotebookCanvas::scroll_into_view(VisualCell *vc, bool center) { // std::cerr << "scrolling into view " << vc << " " << center << std::endl; // if(vc->datacell->cell_type==DataCell::c_input) // std::cerr << "text: " << vc->datacell->textbuf->get_text() << std::endl; // else std::cerr << "not an input cell" << std::endl; Gdk::Rectangle rect; vc->inbox->edit.get_iter_location(vc->inbox->edit.get_buffer()->get_iter_at_mark( vc->inbox->edit.get_buffer()->get_insert()), rect); Gtk::Allocation al=vc->inbox->get_allocation(); Gtk::Adjustment *va=scroll.get_vadjustment(); double upper_visible=va->get_value(); double lower_visible=va->get_value()+va->get_page_size(); if(center) { double aim=std::max(0.0, (double)(al.get_y() + rect.get_y() - 0.5*(va->get_page_size() - rect.get_height()))); aim=std::min(aim, va->get_upper()-va->get_page_size()); va->set_value(aim); } else { if(al.get_y() + rect.get_y() < upper_visible) // cell is above top of view va->set_value(std::max(0.0, (double)(al.get_y() + rect.get_y() - LINE_SPACING))); else { if(al.get_y() + rect.get_y() + rect.get_height() > lower_visible) // cell is below bottom of view va->set_value(al.get_y() + rect.get_y() + rect.get_height() - va->get_page_size() + 20); } } return false; } void NotebookCanvas::scroll_to_start() { Gtk::Adjustment *va=scroll.get_vadjustment(); va->set_value(va->get_lower()); } void NotebookCanvas::scroll_to_end() { Gtk::Adjustment *va=scroll.get_vadjustment(); va->set_value(va->get_upper()-va->get_page_size()); } void NotebookCanvas::scroll_up() { Gtk::Adjustment *va=scroll.get_vadjustment(); va->set_value(std::max(va->get_lower(), va->get_value()-va->get_page_size())); } void NotebookCanvas::scroll_down() { Gtk::Adjustment *va=scroll.get_vadjustment(); va->set_value(std::min(va->get_upper()-va->get_page_size(), va->get_value()+va->get_page_size())); } void NotebookCanvas::select_first_input_cell() { #ifdef DEBUG std::cerr << "select first input" << std::endl; #endif VisualCells_t::iterator it=visualcells.begin(); while(it!=visualcells.end()) { #ifdef DEBUG std::cerr << "inspect" << std::endl; #endif if((*it)->datacell->cell_type==DataCell::c_input) break; ++it; } if(it!=visualcells.end()) { #ifdef DEBUG std::cerr << "notebook going to grab focus" << std::endl; #endif cell_grab_focus(*it); } } void NotebookCanvas::show() { ebox.show(); scroll.show(); scrollbox.show(); // bottomline.show(); VPaned::show(); } XCadabra::XCadabra(modglue::ext_process& cdbproc, const std::string& filename, modglue::main *mm) : font_step(0), brain_wired(0), disable_stacks(false), hglass(Gdk::WATCH), load_file(false), have_received(false), cmm(mm), name(filename), modified(false), running(false), running_last(0), restarting_kernel(false), last_used_id(0), active_canvas(0), active_cell(0), b_kernelversion("Kernel version: not running"), b_help(Gtk::Stock::HELP), b_stop(Gtk::Stock::STOP), b_undo(Gtk::Stock::UNDO), b_redo(Gtk::Stock::REDO), last_configure_width(0), cdb(cdbproc), selected(0), to_scroll_to(0) { std::string res=load_config(); if(res.size()>0) std::cerr << res << std::endl; try { set_icon_from_file(DESTDIR+std::string("/share/pixmaps/cadabra.png")); } catch(Glib::FileError fe) { std::cerr << "cannot open " << DESTDIR+std::string("/share/pixmaps/cadabra.png") << std::endl; } b_stop.set_sensitive(false); b_run.set_label("Run all"); b_run_to.set_label("Run to cursor"); b_run_from.set_label("Run from cursor"); b_kill.set_label("Restart kernel"); parse_mode.push_back(m_discard); #if (GTKMM_VER == 212 || GTKMM_VER == 216) b_help.set_tooltip_text("Show context-sensitive help. Your cursor needs to be over an algorithm (anything starting with '@') or a property (anything starting with '::'). For other types of help, see the help menu."); b_stop.set_tooltip_text("Interrupt the kernel when it is running."); b_run.set_tooltip_text("Evaluate all input cells of the notebook in turn."); b_run_to.set_tooltip_text("Evaluate all input cells from the start of the notebook until and including the cell before the one in which the cursor is currently located."); b_run_from.set_tooltip_text("Evaluate all input cells starting from the one in which the cursor is currently located, until the end of the notebook."); b_kill.set_tooltip_text("Restart the cadabra kernel. This brings you back to the state in which none of the cells in the notebook have been evaluated."); #endif b_cdbstatus.set_alignment( 0.0, 0.5 ); b_kernelversion.set_alignment( 0.0, 0.5 ); b_cdbstatus.set_size_request(200,-1); if(filename.size()>0) load_file=true; update_title(); set_default_size((std::min)(Gdk::Screen::get_default()->get_width()-20, 800), (std::min)(Gdk::Screen::get_default()->get_height()-20, 900)); tex_engine_main.set_font_size(12+(font_step*2)); add(topbox); actiongroup=Gtk::ActionGroup::create(); actiongroup->add( Gtk::Action::create("MenuFile", "_File") ); actiongroup->add( Gtk::Action::create("MenuEdit", "_Edit") ); actiongroup->add( Gtk::Action::create("MenuView", "_View") ); actiongroup->add( Gtk::Action::create("MenuSettings", "_Settings") ); actiongroup->add( Gtk::Action::create("MenuTutorial", "_Tutorial") ); actiongroup->add( Gtk::Action::create("MenuFontSize", "Font size") ); actiongroup->add( Gtk::Action::create("MenuBrainWired", "Brain wired for") ); actiongroup->add( Gtk::Action::create("MenuHelp", "_Help") ); actiongroup->add( Gtk::Action::create("New", Gtk::Stock::NEW), sigc::mem_fun(*this, &XCadabra::on_file_new) ); actiongroup->add( Gtk::Action::create("Open", "_Open"), Gtk::AccelKey("O"), sigc::mem_fun(*this, &XCadabra::on_file_open) ); actiongroup->add( Gtk::Action::create("Save", Gtk::Stock::SAVE), Gtk::AccelKey("S"), sigc::mem_fun(*this, &XCadabra::on_file_save) ); actiongroup->add( Gtk::Action::create("SaveAs", Gtk::Stock::SAVE_AS), sigc::mem_fun(*this, &XCadabra::on_file_save_as) ); actiongroup->add( Gtk::Action::create("Print", Gtk::Stock::PRINT), sigc::mem_fun(*this, &XCadabra::on_file_print) ); actiongroup->add( Gtk::Action::create("ExportTxt", "Export as text..."), sigc::mem_fun(*this, &XCadabra::on_file_export_text) ); actiongroup->add( Gtk::Action::create("Quit", Gtk::Stock::QUIT), sigc::mem_fun(*this, &XCadabra::on_file_quit) ); undo_action_menu = Gtk::Action::create("Undo", Gtk::Stock::UNDO); actiongroup->add( undo_action_menu, Gtk::AccelKey("z"), sigc::mem_fun(*this, &XCadabra::action_undo) ); undo_action_menu->set_sensitive(false); redo_action_menu = Gtk::Action::create("Redo", Gtk::Stock::REDO); actiongroup->add( redo_action_menu, Gtk::AccelKey("z"), sigc::mem_fun(*this, &XCadabra::action_redo) ); redo_action_menu->set_sensitive(false); actiongroup->add( Gtk::Action::create("InsertTeXAbove", "Insert TeX cell above"), Gtk::AccelKey("Up"), sigc::mem_fun(*this, &XCadabra::on_edit_insert_tex_above) ); actiongroup->add( Gtk::Action::create("InsertTeXBelow", "Insert TeX cell below"), Gtk::AccelKey("Down"), sigc::mem_fun(*this, &XCadabra::on_edit_insert_tex_below)); actiongroup->add( Gtk::Action::create("InsertInputAbove", "Insert input cell above"), Gtk::AccelKey("Up"), sigc::mem_fun(*this, &XCadabra::on_edit_insert_input_above) ); actiongroup->add( Gtk::Action::create("InsertInputBelow", "Insert input cell below"), Gtk::AccelKey("Down"), sigc::mem_fun(*this, &XCadabra::on_edit_insert_input_below) ); actiongroup->add( Gtk::Action::create("RemoveActive", "Remove active cell"), Gtk::AccelKey("Delete"), sigc::mem_fun(*this, &XCadabra::on_edit_remove_cell) ); actiongroup->add( Gtk::Action::create("DivideCell", "Divide active cell"), Gtk::AccelKey("D"), sigc::mem_fun(*this, &XCadabra::on_edit_divide_cell) ); actiongroup->add( Gtk::Action::create("SplitView", "Split view"), sigc::mem_fun(*this, &XCadabra::on_view_split) ); actiongroup->add( Gtk::Action::create("CloseView", "Close view"), sigc::mem_fun(*this, &XCadabra::on_view_close) ); Gtk::RadioAction::Group group_font_size; font_action0=Gtk::RadioAction::create(group_font_size, "FontSmall", "Small"); font_action0->property_value()=-1; actiongroup->add( font_action0, sigc::bind(sigc::mem_fun(*this, &XCadabra::on_settings_font_size),-1 )); if(font_step==-1) font_action0->set_active(); font_action1=Gtk::RadioAction::create(group_font_size, "FontMedium", "Medium (default)"); font_action1->property_value()= 0; actiongroup->add( font_action1, sigc::bind(sigc::mem_fun(*this, &XCadabra::on_settings_font_size), 0)); if(font_step==0) font_action1->set_active(); font_action2=Gtk::RadioAction::create(group_font_size, "FontLarge", "Large"); font_action2->property_value()= 2; actiongroup->add( font_action2, sigc::bind(sigc::mem_fun(*this, &XCadabra::on_settings_font_size), 2)); if(font_step==2) font_action2->set_active(); font_action3=Gtk::RadioAction::create(group_font_size, "FontExtraLarge", "Extra large"); font_action3->property_value()= 4; actiongroup->add( font_action3, sigc::bind(sigc::mem_fun(*this, &XCadabra::on_settings_font_size), 4)); if(font_step==4) font_action3->set_active(); // Key wiring Gtk::RadioAction::Group group_brain_wired; brain_wired_action0=Gtk::RadioAction::create(group_brain_wired, "BrainEmacs", "Emacs keys"); brain_wired_action0->property_value() = 0; actiongroup->add( brain_wired_action0, sigc::bind(sigc::mem_fun(*this, &XCadabra::on_settings_brain), 0 )); if(brain_wired==0) brain_wired_action0->set_active(); brain_wired_action1=Gtk::RadioAction::create(group_brain_wired, "BrainWindoze", "Windoze keys"); brain_wired_action1->property_value() = 1; actiongroup->add( brain_wired_action1, sigc::bind(sigc::mem_fun(*this, &XCadabra::on_settings_brain), 1 )); if(brain_wired==1) brain_wired_action1->set_active(); // Construct menu actiongroup->add( Gtk::Action::create("Basics", "Basics"), sigc::bind(sigc::mem_fun(*this, &XCadabra::on_tutorial_open),0) ); actiongroup->add( Gtk::Action::create("Derivatives", "Derivatives"), sigc::bind(sigc::mem_fun(*this, &XCadabra::on_tutorial_open),1) ); actiongroup->add( Gtk::Action::create("Relativity", "Relativity"), sigc::bind(sigc::mem_fun(*this, &XCadabra::on_tutorial_open),2) ); actiongroup->add( Gtk::Action::create("Spinors", "Spinors"), sigc::bind(sigc::mem_fun(*this, &XCadabra::on_tutorial_open),3) ); actiongroup->add( Gtk::Action::create("About", Gtk::Stock::ABOUT), sigc::mem_fun(*this, &XCadabra::on_help_about) ); actiongroup->add( Gtk::Action::create("CitingInfo", "Citing cadabra"), sigc::mem_fun(*this, &XCadabra::on_help_citing) ); actiongroup->add( Gtk::Action::create("AllProperties", "Properties")); actiongroup->add( Gtk::Action::create("AllAlgorithms", "Algorithms")); actiongroup->add( Gtk::Action::create("AllReserved", "Reserved node names")); actiongroup->add( Gtk::Action::create("ContextHelp", "Current object"), Gtk::AccelKey("F1"), sigc::mem_fun(*this, &XCadabra::on_help_context) ); // actiongroup->add( Gtk::Action::create("AutoComplete", "Auto-complete"), // Gtk::AccelKey(""), // sigc::mem_fun(*this, &XCadabra::on_autocomplete) ); uimanager = Gtk::UIManager::create(); uimanager->insert_action_group(actiongroup); add_accel_group(uimanager->get_accel_group()); Glib::ustring ui_info = "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; // " " // " " // " " // " " // " " // " " uimanager->add_ui_from_string(ui_info); Gtk::Widget *menubar = uimanager->get_widget("/MenuBar"); topbox.pack_start(*menubar, Gtk::PACK_SHRINK); // // add the lot to the window // topbox.pack_start(menubar, Gtk::PACK_SHRINK); topbox.pack_start(supermainbox, true, true); topbox.pack_start(statusbarbox, false, false); supermainbox.pack_start(mainbox, true, true); // The three main widgets mainbox.pack_start(buttonbox, Gtk::PACK_SHRINK, 0); buttonbox.pack_start(statusbox, Gtk::PACK_EXPAND_WIDGET, 0); b_cdbstatus.set_justify(Gtk::JUSTIFY_LEFT); statusbarbox.pack_start(b_cdbstatus); b_kernelversion.set_justify(Gtk::JUSTIFY_LEFT); statusbarbox.pack_start(b_kernelversion); // statusbarbox.pack_start(progressbarvbox); statusbarbox.pack_start(progressbar1); statusbarbox.pack_start(progressbar2); progressbar1.set_size_request(200,-1); progressbar2.set_size_request(200,-1); // buttonbox.pack_start(b_undo, Gtk::PACK_SHRINK); // buttonbox.pack_start(b_redo, Gtk::PACK_SHRINK); buttonbox.pack_start(b_help, Gtk::PACK_SHRINK); buttonbox.pack_start(b_run, Gtk::PACK_SHRINK); buttonbox.pack_start(b_run_to, Gtk::PACK_SHRINK); buttonbox.pack_start(b_run_from, Gtk::PACK_SHRINK); buttonbox.pack_start(b_stop, Gtk::PACK_SHRINK); buttonbox.pack_start(b_kill, Gtk::PACK_SHRINK); // b_undo.signal_clicked().connect(sigc::mem_fun(*this, &XCadabra::action_undo)); // b_redo.signal_clicked().connect(sigc::mem_fun(*this, &XCadabra::action_redo)); b_help.signal_clicked().connect(sigc::mem_fun(*this, &XCadabra::on_help_context)); b_stop.signal_clicked().connect(sigc::mem_fun(*this, &XCadabra::on_stop)); b_kill.signal_clicked().connect(sigc::mem_fun(*this, &XCadabra::on_kill)); b_run.signal_clicked().connect(sigc::mem_fun(*this, &XCadabra::on_run)); b_run_to.signal_clicked().connect(sigc::mem_fun(*this, &XCadabra::on_run_to)); b_run_from.signal_clicked().connect(sigc::mem_fun(*this, &XCadabra::on_run_from)); // Setup the exception handler for exceptions thrown inside signal handlers (mainly // to catch LaTeX errors which occur during 'on_show' of the TeXView widget). Glib::add_exception_handler(sigc::mem_fun(*this, &XCadabra::on_signal_exception)); // We always have at least one canvas: this one canvasses.push_back(manage( new NotebookCanvas(*this) )); mainbox.pack_start(*canvasses.back(), Gtk::PACK_EXPAND_WIDGET, 0); // canvasses[0]->to_cdb.connect(sigc::mem_fun(*this, &XCadabra::handle_editbox_output)); active_canvas=canvasses[0]; show_all(); // Setup an empty notebook and add a single empty input cell. Glib::RefPtr newcell(new DataCell(DataCell::c_input)); add_cell(newcell, Glib::RefPtr() ); show_cell(newcell); active_canvas->cell_grab_focus(newcell); modified=false; kernel_idle(); update_title(); } bool XCadabra::on_key_press_event(GdkEventKey* event) { switch(event->keyval) { case GDK_Home: if(brain_wired==0 || (event->state&Gdk::CONTROL_MASK) ) { active_canvas->scroll_to_start(); return true; // if we don't return immediately, selections will go away } else break; case GDK_End: if(brain_wired==0 || (event->state&Gdk::CONTROL_MASK) ) { active_canvas->scroll_to_end(); return true; // if we don't return immediately, selections will go away } else break; case GDK_Page_Up: active_canvas->scroll_up(); return true; // if we don't return immediately, selections will go away case GDK_Page_Down: active_canvas->scroll_down(); return true; // if we don't return immediately, selections will go away case 108: if( (event->state&Gdk::CONTROL_MASK) ) { // Ctrl-L: center display set_next_into_view(active_cell); // active_canvas->scroll_into_view(active_cell, true); return true; // if we don't return immediately, selections will go away } break; case GDK_Tab: if(on_autocomplete()) return true; // prevent normal Tab action case '/': case 'z': if( (event->state&Gdk::CONTROL_MASK) ) { action_undo(); return true; } break; case '?': case 'Z': if( (event->state&Gdk::CONTROL_MASK) ) { action_redo(); return true; } break; } // Now first handle normal Gtk events so that we can skip to other cells // etc. After that we update the notebook position if required. bool retval=Window::on_key_press_event(event); if(active_cell && event->keyval < 65000) // FIXME: how to find dead keys? set_next_into_view(active_cell); //active_canvas->scroll_into_view(active_cell); return retval; } bool XCadabra::callmm(Glib::IOCondition, int fd) { if(!(cmm->select_callback(fd))) { connections[fd].disconnect(); connections.erase(fd); } return true; } void XCadabra::add_canvas() { canvasses.push_back(manage( new NotebookCanvas(*this) )); canvasses[canvasses.size()-2]->pack2(*canvasses.back()); // canvasses.back()->to_cdb.connect(sigc::mem_fun(*this, &XCadabra::handle_editbox_output)); // Make it display all DataCells DataCells_t::iterator it=datacells.begin(); while(it!=datacells.end()) { canvasses.back()->add_cell(*it, Glib::RefPtr()); canvasses.back()->show_cell(*it); ++it; } canvasses.back()->show(); // Set up selection mechanisms. For Maple, it seems that we need LENGTH. // Also, we will put normal, non-utf8-dressed text in TEXT, instead of the // \x{...} stuff that the TextView widget normally spits out. // selection_add_target(GDK_SELECTION_PRIMARY, Gtk::TargetEntry("LENGTH", 1)); // selection_add_target(GDK_SELECTION_PRIMARY, Gtk::TargetEntry("TEXT", 2)); } void XCadabra::on_stop() { kill(cdb.get_pid(), SIGINT); } void XCadabra::on_kill() { restarting_kernel=true; // *(cdb.output_pipe("stdin")) << "@quit;\n" << std::flush; // There is no point in shutting down cadabra nicely (as we did with // the statement above in earlier versions); instead, we send a full // blown SIGKILL. if(kill(cdb.get_pid(),0)==0) kill(cdb.get_pid(), SIGKILL); b_cdbstatus.set_text(" Status: Restarting kernel..."); b_kernelversion.set_text("Kernel: not running"); // We now wait for the process to terminate properly and // modglue to send us a signal about that. // cdb.terminate(); // cdb.fork(); // *(cdb.output_pipe("stdin")) << "@print_status{true};\n" << std::flush; // b_cdbstatus.set_text("Status: Kernel restarted, idle."); } void XCadabra::on_run() { get_window()->set_cursor(hglass); running=true; #if (GLIBMM_VER == 216) running_last.reset(); #else running_last.clear(); #endif b_cdbstatus.set_text(" Status: Executing notebook."); b_stop.set_sensitive(true); active_canvas->select_first_input_cell(); // Upon returning from this function, the main loop will start // executing the notebook cells one by one as long as 'running=true'. } void XCadabra::on_run_to() { if(active_cell!=0) { get_window()->set_cursor(hglass); running=true; running_last=active_cell->datacell; b_stop.set_sensitive(true); b_cdbstatus.set_text(" Status: Executing until cursor."); active_canvas->select_first_input_cell(); } // Upon returning from this function, the main loop will start // executing the notebook cells one by one as long as 'running=true'. } void XCadabra::on_run_from() { if(active_cell!=0) { get_window()->set_cursor(hglass); running=true; #if (GLIBMM_VER == 216) running_last.reset(); #else running_last.clear(); #endif b_cdbstatus.set_text(" Status: Executing from cursor."); b_stop.set_sensitive(true); active_canvas->cell_grab_focus(active_cell); } } void XCadabra::on_help_about() { Gtk::AboutDialog md; md.set_name("XCadabra"); md.set_website("http://cadabra.phi-sci.com/"); md.set_website_label("cadabra website"); md.set_version(RELEASE); md.set_copyright("\xC2\xA9 2006-2011 Kasper Peeters"); md.set_comments("Graphical user interface for the cadabra symbolic computer algebra system."); md.set_license("XCadabra and Cadabra are available under the Gnu General Public License version 2.\n\nIf you use Cadabra or even just play with it, I would like to hear about it. Please send me an email so that I can get an idea of who is interested in this program.\n\nIf you use Cadabra in your own work, please cite both\n\nKasper Peeters\n\"A field-theory motivated approach to computer algebra\"\ncs.sc/0608005\nComput. Phys. Commun 176 (2007) 550\n\nKasper Peeters\n\"Introducing Cadabra: a symbolic computer algebra system for field theory problems\"\nhep-th/0701238\n\nThank you!"); #if (GTKMM_VER == 28 || GTKMM_VER == 212 || GTKMM_VER == 216) md.set_wrap_license(true); #endif std::vector authors; authors.push_back("Kasper Peeters \n"); authors.push_back("with contributions by:"); authors.push_back("\tJosé M. Martín-García"); authors.push_back("\tJames Allen"); md.set_authors(authors); md.run(); } void XCadabra::on_help_algorithms(const std::string& algorithm) { help_window.on_help_context_link(CadabraHelp::t_algorithm, algorithm.substr(1)); } void XCadabra::on_help_properties(const std::string& property) { help_window.on_help_context_link(CadabraHelp::t_property, property.substr(2)); } void XCadabra::on_help_reserved(const std::string& reserved) { help_window.on_help_context_link(CadabraHelp::t_texcommand, reserved.substr(1)); } void XCadabra::on_help_citing() { std::ostringstream str; str << "Cadabra citing information"; Gtk::MessageDialog md(str.str()); md.set_secondary_text("If you use Cadabra to write a paper, please cite both\n\nKasper Peeters\n\"A field-theory motivated approach to computer algebra\"\ncs.sc/0608005\nComput. Phys. Commun. 176 (2007) 550\n\nKasper Peeters\n\"Introducing Cadabra: a symbolic computer algebra system for field theory problems\"\nhep-th/0701238\n\nThank you!"); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); // md.set_position(Gtk::WIN_POS_CENTER_ALWAYS); md.run(); } void XCadabra::insert_at_mark(const std::string instxt) { // Find the Gtk::TextBuffer corresponding to the current cell. Glib::RefPtr buf; switch(active_cell->datacell->cell_type) { case DataCell::c_input: buf=active_cell->datacell->textbuf; break; case DataCell::c_tex: buf=active_cell->datacell->texbuf->tex_source; break; default: return; } // Gtk::TextBuffer::iterator it=buf->get_iter_at_mark(buf->get_insert()); // --it; buf->insert_at_cursor(instxt); // for(int i=instxt.size(); i>0; --i) // ++it; // buf->place_cursor(buf->end()); // active_canvas->cell_grab_focus(active_cell); } bool XCadabra::current_objtype_and_name(CadabraHelp::objtype_t& objtype, std::string& helpname) { // Find the Gtk::TextBuffer corresponding to the current cell. Glib::RefPtr buf; switch(active_cell->datacell->cell_type) { case DataCell::c_input: buf=active_cell->datacell->textbuf; break; case DataCell::c_tex: buf=active_cell->datacell->texbuf->tex_source; break; default: return false; } Gtk::TextBuffer::iterator it=buf->get_iter_at_mark(buf->get_insert()); std::string before=buf->get_slice(buf->begin(), it); std::string after =buf->get_slice(it, buf->end()); if(! (before.size()==0 && after.size()==0) ) { // We provide help for properties, algorithms and reserved node names. // Properties are delimited // to the left by '::' and to the right by anything non-alnum. Algorithms // are delimited to the left by '@' and to the right by anything non-alnum or // non '_'. Reserved node names are TeX symbols, starting with '\'. // // So scan the 'before' string for a left-delimiter and the 'after' string // for a right-delimiter. int lpos=before.size()-1; bool accepted_underscore=false; while(lpos>=0) { if(before[lpos]==':' && lpos>0 && before[lpos-1]==':') { objtype=CadabraHelp::t_property; break; } if(before[lpos]=='\\') { objtype=CadabraHelp::t_texcommand; break; } if(before[lpos]=='@') { objtype=CadabraHelp::t_algorithm; break; } if(before[lpos]=='_') accepted_underscore=true; else if(isalnum(before[lpos])==0) return false; --lpos; } if(objtype==CadabraHelp::t_none) return false; if(accepted_underscore && objtype==CadabraHelp::t_property) return false; ++lpos; size_t rpos=0; while(rpos::iterator it, itend; std::string candidate; bool options_exist=false; bool alg_or_prop=true; if(objtype==CadabraHelp::t_algorithm) { it=algorithm_set.begin(); itend=algorithm_set.end(); } else if(objtype==CadabraHelp::t_property) { it=property_set.begin(); itend=property_set.end(); } else { alg_or_prop=false; helpname="\\"+helpname; for(unsigned int i=0; irunning=false; ++dit; } restarting_kernel=false; // return 'false' to keep the main loop running. return false; } void XCadabra::disconnect_io_signals() { std::map::iterator it=connections.begin(); while(it!=connections.end()) { it->second.disconnect(); ++it; } connections.clear(); } void XCadabra::connect_io_signals() { assert(connections.size()==0); std::vector fds; cmm->fds_to_watch(fds); for(unsigned int i=0; i act) { // std::cerr << "Adding an action." << std::endl; while(redo_stack.size()>0) redo_stack.pop(); redo_action_menu->set_sensitive(false); undo_action_menu->set_sensitive(true); undo_stack.push(act); act->execute(*this); return true; } void XCadabra::action_undo() { // std::cerr << "undo: " << undo_stack.size() // << " redo: " << redo_stack.size() << std::endl; if(undo_stack.size()>0) { disable_stacks=true; undo_stack.top()->revert(*this); redo_stack.push(undo_stack.top()); undo_stack.pop(); disable_stacks=false; redo_action_menu->set_sensitive(true); if(undo_stack.size()==0) undo_action_menu->set_sensitive(false); } } void XCadabra::action_redo() { // std::cerr << "undo: " << undo_stack.size() // << " redo: " << redo_stack.size() << std::endl; if(redo_stack.size()>0) { disable_stacks=true; redo_stack.top()->execute(*this); undo_stack.push(redo_stack.top()); redo_stack.pop(); disable_stacks=false; undo_action_menu->set_sensitive(true); if(redo_stack.size()==0) redo_action_menu->set_sensitive(false); } } Glib::RefPtr XCadabra::add_cell(Glib::RefPtr newcell, Glib::RefPtr ref, bool before) { modified=true; update_title(); // First the data object, of which there is only one per cell. if(ref==0) datacells.push_back(newcell); else { DataCells_t::iterator fnd=find(datacells.begin(), datacells.end(), ref); if(fnd==datacells.end()) { datacells.push_back(newcell); } else { if(!before) { do { ++fnd; } while( fnd!=datacells.end() && ( (*fnd)->cell_type==DataCell::c_output || (*fnd)->cell_type==DataCell::c_error ) ); } datacells.insert(fnd, newcell); } } // Gtk::Allocation al= get_allocation(); try { switch(newcell->cell_type) { case DataCell::c_output: newcell->texbuf->generate("\\begin{dmath*}[compact,spread=2pt]\n","\\end{dmath*}\n"); break; case DataCell::c_comment: newcell->texbuf->generate("\\begin{verbatim}\n","\\end{verbatim}\n"); break; case DataCell::c_texcomment: newcell->texbuf->generate("{\\small ","}"); break; case DataCell::c_input: newcell->textbuf->signal_changed().connect(sigc::mem_fun(this, &XCadabra::input_cell_modified)); // Connect insert/delete signals to undo stack handler. newcell->textbuf->signal_insert().connect( sigc::bind >(sigc::mem_fun(this, &XCadabra::on_my_insert), newcell), false); newcell->textbuf->signal_erase().connect( sigc::bind >(sigc::mem_fun(this, &XCadabra::on_my_erase), newcell), false); break; case DataCell::c_error: newcell->texbuf->generate("{\\color[named]{Red}", "}"); break; case DataCell::c_tex: newcell->texbuf->generate("",""); newcell->textbuf->signal_changed().connect(sigc::mem_fun(this, &XCadabra::tex_cell_modified)); // Connect insert/delete signals to undo/redo stack handler. newcell->texbuf->tex_source->signal_insert().connect( sigc::bind >(sigc::mem_fun(this, &XCadabra::on_my_insert), newcell), false); newcell->texbuf->tex_source->signal_erase().connect( sigc::bind >(sigc::mem_fun(this, &XCadabra::on_my_erase), newcell), false); break; } // Now we have to tell all NotebookCanvas objects to create a // view on the just created DataCell. for(unsigned int i=0; iadd_cell(newcell, ref, before); } catch(std::exception& ex) { kernel_idle(); size_t lines=1; std::string what=ex.what(); for(size_t i=0; i tb=Gtk::TextBuffer::create(); Gtk::ScrolledWindow sw; Gtk::Button ok(Gtk::Stock::OK); tb->set_text(ex.what()); md.get_vbox()->add(sw); md.add_button(Gtk::Stock::OK, 1); sw.add(tv); tv.set_buffer(tb); tv.set_editable(false); md.set_size_request(400,300); md.show_all(); md.run(); } } return newcell; } void XCadabra::show_cell(Glib::RefPtr datacell) { for(unsigned int i=0; ishow_cell(datacell); } bool XCadabra::handle_editbox_output(std::string str, NotebookCanvas *can, VisualCell *vis) { #ifdef DEBUG std::cerr << "handling edit box" << std::endl; #endif // Disable this cell until output has been received, so we // don't get it twice. if(vis->datacell->running==false) { vis->datacell->running=true; // Remove any old error boxes until the next // Now run the input through cadabra. #ifdef DEBUG std::cerr << "sending to cdb " << str << std::endl; #endif b_cdbstatus.set_text(" Status: Kernel busy."); get_window()->set_cursor(hglass); ++last_used_id; id_to_datacell[last_used_id] = vis->datacell; *(cdb.output_pipe("stdin")) << "#cellstart " << last_used_id << "\n" << str << "\n" << "#cellend\n" << std::flush; #ifdef DEBUG std::cerr << "sending of cell # " << last_used_id << " done" << std::endl; #endif } return true; } void XCadabra::on_my_insert(const Gtk::TextIter& pos, const Glib::ustring& text, int bytes, Glib::RefPtr dc) { if(disable_stacks) return; while(redo_stack.size()>0) redo_stack.pop(); redo_action_menu->set_sensitive(false); undo_action_menu->set_sensitive(true); Glib::RefPtr buf; if(dc->cell_type == DataCell::c_input) buf = dc->textbuf; else buf = dc->texbuf->tex_source; // FIXME: we could merge undos here, saves memory. undo_stack.push(Glib::RefPtr(new ActionAddText(dc, std::distance(buf->begin(), pos), text))); } void XCadabra::on_my_erase(const Gtk::TextIter& start, const Gtk::TextIter& end, Glib::RefPtr dc) { if(disable_stacks) return; while(redo_stack.size()>0) redo_stack.pop(); redo_action_menu->set_sensitive(false); undo_action_menu->set_sensitive(true); Glib::RefPtr buf; if(dc->cell_type == DataCell::c_input) buf = dc->textbuf; else buf = dc->texbuf->tex_source; undo_stack.push(Glib::RefPtr(new ActionRemoveText(dc, std::distance(buf->begin(), start), std::distance(buf->begin(), end), buf->get_slice(start, end)))); } void XCadabra::handle_on_grab_focus(NotebookCanvas *can, VisualCell *vis) { #ifdef DEBUG std::cerr << "focus grabbed " << can << " " << vis << std::endl; #endif active_canvas=can; active_cell=vis; if(selected) { selected->outbox->set_state(Gtk::STATE_NORMAL); selected=0; } if(running && vis) { if(running_last==active_cell->datacell) { kernel_idle(); // while (gtk_events_pending ()) // gtk_main_iteration (); // make sure this last cell is in view // active_canvas->scroll_into_view(active_cell); set_next_into_view(active_cell); } else { Glib::RefPtr textbuf=active_cell->datacell->textbuf; std::string tmp(trim(textbuf->get_text(textbuf->begin(), textbuf->end()))); if(tmp[0]!='#' && tmp[tmp.size()-1]!=';' && tmp[tmp.size()-1]!=':' && tmp[tmp.size()-1]!='.' ) { #ifdef DEBUG std::cerr << "cell does not end with delimiter" << std::endl; #endif kernel_idle(); // while (gtk_events_pending ()) // gtk_main_iteration (); // running stops, so we scroll this cell into view // active_canvas->scroll_into_view(active_cell); set_next_into_view(active_cell); } else { #ifdef DEBUG std::cerr << "executing cell\n" << tmp << std::endl; #endif // This logic also appears in handle_editbox_output; sync! ++last_used_id; id_to_datacell[last_used_id] = active_cell->datacell; *(cdb.output_pipe("stdin")) << "#cellstart " << last_used_id << "\n" << tmp << "\n" << "#cellend\n" << std::flush; } } } } bool XCadabra::handle_visibility_toggle(GdkEventButton *, NotebookCanvas *can, VisualCell *vis) { // If this action wants to close the cell, update the TeX image first (this will if(vis->datacell->tex_hidden==false) if(vis->texbox->edit.is_modified) if(handle_tex_update_request(vis->datacell->textbuf->get_text(), can, vis)==false) return false; // Now change the visibility vis->datacell->tex_hidden = !vis->datacell->tex_hidden; for(unsigned int i=0; ivisualcells.begin(); while(it!=canvasses[i]->visualcells.end()) { if((*it)->datacell==vis->datacell) { (*it)->texbox->set_folded(vis->datacell->tex_hidden); break; } ++it; } } return true; } bool XCadabra::handle_outbox_select(GdkEventButton *, NotebookCanvas *can, VisualCell *vis) { Glib::RefPtr refClipboard = Gtk::Clipboard::get(GDK_SELECTION_PRIMARY); if(selected) { selected->outbox->set_state(Gtk::STATE_NORMAL); if(selected==vis) { refClipboard->set_text(""); selected=0; return true; } } selected=vis; vis->outbox->set_state(Gtk::STATE_PRELIGHT); std::string cpystring=vis->datacell->texbuf->tex_source->get_text(); size_t pos=cpystring.find("\\specialcolon{}"); if(pos!=std::string::npos) cpystring.replace(pos, 15, " :"); // Setup clipboard handling clipboard_txt = cpystring; clipboard_cdb = vis->datacell->cdbbuf; std::list listTargets; if(clipboard_cdb.size()>0) listTargets.push_back( Gtk::TargetEntry("cadabra") ); listTargets.push_back( Gtk::TargetEntry("UTF8_STRING") ); listTargets.push_back( Gtk::TargetEntry("TEXT") ); refClipboard->set( listTargets, sigc::mem_fun(this, &XCadabra::on_clipboard_get), sigc::mem_fun(this, &XCadabra::on_clipboard_clear) ); return true; } bool XCadabra::handle_tex_update_request(std::string, NotebookCanvas *can, VisualCell *vis) { // First re-generate the image. try { vis->texbox->texview.texbuf->generate("",""); vis->texbox->edit.is_modified=false; } catch(std::exception& ex) { kernel_idle(); Gtk::MessageDialog md(ex.what()); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); md.run(); return false; } // Now walk through all TeXInput cells and update the Image widget. for(unsigned int i=0; ivisualcells.begin(); while(it!=canvasses[i]->visualcells.end()) { if((*it)->datacell==vis->datacell) { (*it)->texbox->texview.update_image(); break; } ++it; } } return true; } XCadabra::~XCadabra() { } bool XCadabra::on_configure_event(GdkEventConfigure *cfg) { if(cfg->width != last_configure_width) tex_engine_main.set_geometry(cfg->width-20-35); bool ret=Gtk::Window::on_configure_event(cfg); if(cfg->width != last_configure_width) { last_configure_width = cfg->width; try { tex_engine_main.convert_all(); } catch(TeXEngine::TeXException& ex) { generic_error_popup(std::string(ex.what())); } for(unsigned int i=0; iredraw_cells(); } return ret; } bool XCadabra::on_delete_event(GdkEventAny* event) { if(quit_safeguard()) { // cdb.terminate(); // Ensure that the kernel is really gone, not just stuck in a loop. if(cdb.get_pid()!=0) if(kill(cdb.get_pid(), 0)==0) kill(cdb.get_pid(), SIGKILL); Gtk::Window::on_delete_event(event); Gtk::Main::quit(); return false; } else return true; } void XCadabra::generic_error_popup(const std::string& err) const { size_t lines=1; std::string what=err; for(size_t i=0; i tb=Gtk::TextBuffer::create(); Gtk::ScrolledWindow sw; Gtk::Button ok(Gtk::Stock::OK); tb->set_text(err); md.get_vbox()->add(sw); md.add_button(Gtk::Stock::OK, 1); sw.add(tv); tv.set_buffer(tb); tv.set_editable(false); md.set_size_request(400,300); md.show_all(); md.run(); } } void XCadabra::on_signal_exception() { #ifdef DEBUG std::cerr << "on_signal_exception" << std::endl; #endif try { throw; } catch(TeXEngine::TeXException& ex) { generic_error_popup(std::string(ex.what())); } } void XCadabra::input_cell_modified() { if(!modified) { modified=true; update_title(); } } void XCadabra::tex_cell_modified() { if(!modified) { modified=true; update_title(); } } void XCadabra::remove_noninput_below(Glib::RefPtr dc) { if(selected) { selected->outbox->set_state(Gtk::STATE_NORMAL); selected=0; } DataCells_t::iterator it=datacells.begin(); while(it!=datacells.end()) { if((*it)==dc) { ++it; while(it!=datacells.end() && ( (*it)->cell_type==DataCell::c_output || (*it)->cell_type==DataCell::c_comment || (*it)->cell_type==DataCell::c_texcomment || (*it)->cell_type==DataCell::c_error) ) { for(unsigned int i=0; iremove_cell(*it); } it=datacells.erase(it); } return; } ++it; } } void XCadabra::kernel_idle() { running=false; b_cdbstatus.set_text(" Status: Kernel idle."); get_window()->set_cursor(); b_stop.set_sensitive(false); } bool XCadabra::receive(modglue::ipipe& p) { static std::string str; static std::string comment; static std::string error; static bool error_occurred=false; static bool last_was_prompt=true; // avoid repeated empty cells static bool in_cell=false; // prompts only get honored outside cells static Glib::RefPtr cp, origcell; static std::vector > cells_to_show; have_received=true; while(std::getline(p,str)) { #ifdef DEBUG std::cerr << "rec: " << str << std::endl; #endif if(str.substr(0,10)=="#cellstart") { std::istringstream ss(str.substr(11)); int help; ss >> help; assert(id_to_datacell.find(help)!=id_to_datacell.end()); cp=id_to_datacell[help]; #ifdef DEBUG std::cerr << "original cell = " << cp->textbuf->get_text() << std::endl; #endif remove_noninput_below(cp); origcell=cp; in_cell=true; comment=""; continue; } else if(str=="#cellend") { in_cell=false; last_was_prompt=false; if(trim(comment).size()!=0 && trim(comment)!=">") { Glib::RefPtr newcell(new DataCell(DataCell::c_comment, trim(comment))); cp=add_cell(newcell, cp, false); cells_to_show.push_back(newcell); } try { tex_engine_main.convert_all(); } catch(TeXEngine::TeXException& ex) { generic_error_popup(std::string(ex.what())); } for(size_t i=0; i") { parse_mode.push_back(m_comment); last_was_prompt=false; continue; } else if(str=="") { parse_mode.pop_back(); last_was_prompt=false; continue; } else if(str=="") { parse_mode.push_back(m_texcomment); last_was_prompt=false; continue; } else if(str=="") { parse_mode.pop_back(); last_was_prompt=false; if(trim(comment).size()!=0 && trim(comment)!=">") { Glib::RefPtr newcell(new DataCell(DataCell::c_texcomment, trim(comment))); cp=add_cell(newcell, cp, false); cells_to_show.push_back(newcell); } comment=""; continue; } else if(str=="") { parse_mode.push_back(m_status); last_was_prompt=false; continue; } else if(str=="") { parse_mode.pop_back(); continue; } else if(str=="") { parse_mode.push_back(m_plain); plain=""; last_was_prompt=false; continue; } else if(str=="") { parse_mode.pop_back(); last_was_prompt=false; continue; } else if(str=="") { progress=""; progress_todo=-1; progress_done=-1; progress_count=-1; parse_mode.push_back(m_progress); continue; } else if(str=="") { std::ostringstream ss; if(progress_todo>0) ss << progress << "..." << " (" << progress_done << " of " << progress_todo << ")"; else ss << progress << "..."; if(progress_count==1) { progressbar1.set_text(ss.str()); if(progress_todo==0) progressbar1.set_fraction(0); else progressbar1.set_fraction(std::min(1.0,progress_done/(1.0*progress_todo))); } else { progressbar2.set_text(ss.str()); if(progress_todo==0) progressbar2.set_fraction(0); else progressbar2.set_fraction(std::min(1.0,progress_done/(1.0*progress_todo))); } parse_mode.pop_back(); continue; } else if(str=="") { parse_mode.push_back(m_error); last_was_prompt=false; error_occurred=true; continue; } else if(str=="") { parse_mode.pop_back(); if(trim(error).size()!=0) { Glib::RefPtr newcell(new DataCell(DataCell::c_error, trim(error))); kernel_idle(); cp=add_cell(newcell, cp, false); cells_to_show.push_back(newcell); // // make previous input cell active // DataCells_t::iterator dit=datacells.begin(); // while(dit!=datacells.end()) { // if((*dit)==newcell) { // while(dit!=datacells.begin()) { // // } // } // prevcell=(*dit); // ++dit; // } } error=""; last_was_prompt=false; continue; } else if(str=="") { parse_mode.push_back(m_eqno); last_was_prompt=false; continue; } else if(str=="") { parse_mode.pop_back(); continue; } else if(str=="") { parse_mode.push_back(m_eq); last_was_prompt=false; continue; } else if(str=="") { parse_mode.pop_back(); if(eq.size()!=0) { Glib::RefPtr newcell(new DataCell(DataCell::c_output, eqno+"\\specialcolon{}= "+eq)); newcell->cdbbuf=plain; cp=add_cell(newcell, cp, false); cells_to_show.push_back(newcell); } eq=""; eqno=""; plain=""; last_was_prompt=false; // if(!running) // kernel_idle(); // if(origcell) { // origcell->running=false; //#if (GLIBMM_VER == 216) // origcell.reset(); //#else // origcell.clear(); //#endif // } continue; } else if(str=="") { parse_mode.push_back(m_property); last_was_prompt=false; continue; } else if(str=="") { add_property_help(property); property=""; parse_mode.pop_back(); continue; } else if(str=="") { parse_mode.push_back(m_algorithm); last_was_prompt=false; continue; } else if(str=="") { add_algorithm_help(algorithm); algorithm=""; parse_mode.pop_back(); continue; } else if(str=="") { parse_mode.push_back(m_reserved); last_was_prompt=false; continue; } else if(str=="") { add_reserved_help(reserved); reserved=""; parse_mode.pop_back(); continue; } else if(trim(str).substr(0,1)==">") { #ifdef DEBUG std::cerr << "received empty prompt" << std::endl; #endif progressbar2.set_fraction(0); progressbar1.set_fraction(0); progressbar2.set_text(" "); progressbar1.set_text(" "); if(!last_was_prompt && !in_cell) { if(!running) kernel_idle(); last_was_prompt=true; if(error_occurred) { error_occurred=false; // re-enable original cell if(origcell) { origcell->running=false; #if (GLIBMM_VER == 216) origcell.reset(); #else origcell.clear(); #endif } } else { // everything hunky dorey if(datacells.back()==cp || cp==0 ) { // we are at the last cell of the notebook if(datacells.size()>0 && datacells.back()->cell_type==DataCell::c_input && trim(datacells.back()->textbuf->get_text()).size()==0 ) { // we still have an empty cell below if(restarting_kernel) { restarting_kernel=false; active_canvas->cell_grab_focus(active_cell); } else { // FIXME: FOCUS // active_canvas->cell_grab_focus(datacells.back()); } // while (gtk_events_pending ()) // gtk_main_iteration (); // active_canvas->scroll_into_view(active_cell); set_next_into_view(active_cell); } else { // this last cell is not an input cell; add a new input cell Glib::RefPtr newcell(new DataCell(DataCell::c_input, "")); action_add(Glib::RefPtr(new ActionAddCell(newcell, cp, false))); cp = newcell; show_cell(newcell); if(!running) // grab focus if we are in interactive mode active_canvas->cell_grab_focus(cp); } if(restarting_kernel) { restarting_kernel=false; active_canvas->cell_grab_focus(active_cell); } // while (gtk_events_pending ()) // gtk_main_iteration (); // active_canvas->scroll_into_view(active_cell); set_next_into_view(active_cell); // re-enable original cell (mark it non-running) if(origcell) { origcell->running=false; #if (GLIBMM_VER == 216) origcell.reset(); #else origcell.clear(); #endif } } else { // still more cells below if(restarting_kernel) { restarting_kernel=false; active_canvas->cell_grab_focus(active_cell); } else { // put cursor in the next input cell DataCells_t::iterator it=datacells.begin(); while(it!=datacells.end()) { if(*it==cp) { ++it; while(it!=datacells.end() && (*it)->cell_type!=DataCell::c_input) ++it; if(it==datacells.end()) { Glib::RefPtr newcell(new DataCell(DataCell::c_input, "")); action_add(Glib::RefPtr(new ActionAddCell(newcell, cp, false))); cp = newcell; // cp=add_cell(newcell, cp, false); // HERE show_cell(newcell); active_canvas->cell_grab_focus(cp); } else { active_canvas->cell_grab_focus(*it); } // re-enable original cell if(origcell) { origcell->running=false; #if (GLIBMM_VER == 216) origcell.reset(); #else origcell.clear(); #endif } break; } ++it; } if(!running) { // put cell in view // while (gtk_events_pending ()) // gtk_main_iteration (); // active_canvas->scroll_into_view(active_cell); set_next_into_view(active_cell); } } } } } else str="\n"; } switch(parse_mode.back()) { case m_eq: eq+=str; if(str[str.size()-1]=='%') eq+="\n"; break; case m_eqno: eqno+=str; break; case m_status: case m_discard: break; case m_property: property+=str; break; case m_algorithm: algorithm+=str; break; case m_reserved: reserved+=str; break; case m_comment: case m_texcomment: if(trim(str).size()>0) comment+=str+"\n"; break; case m_error: error+=str+"\n"; break; case m_plain: plain+=str; break; case m_progress: if(progress=="") progress=str; else if(progress_todo==-1) progress_todo=atoi(str.c_str()); else if(progress_done==-1) progress_done=atoi(str.c_str()); else progress_count=atoi(str.c_str()); break; } } p.clear(); if(load_file) { load_file=false; #ifdef DEBUG std::cerr << "Loading file..." << std::endl; #endif std::string tmp=name; std::string res=load(tmp, true); if(res.size()>0) { Gtk::MessageDialog md("Error loading document "+tmp); md.set_secondary_text(res); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); md.run(); name=""; } else { name=tmp; Glib::RefPtr newcell(new DataCell(DataCell::c_input)); add_cell(newcell, Glib::RefPtr()); show_cell(newcell); active_canvas->select_first_input_cell(); } modified=false; update_title(); } return true; } bool XCadabra::receive_err(modglue::ipipe& p) { std::string str; while(std::getline(p,str)) { accumulated_error+=str; } p.clear(); return true; } void XCadabra::on_file_new() { if(quit_safeguard(false)) { clear(); Glib::RefPtr newcell(new DataCell(DataCell::c_input)); add_cell(newcell, Glib::RefPtr() ); show_cell(newcell); active_canvas->cell_grab_focus(newcell); modified=false; update_title(); on_kill(); } } void XCadabra::on_file_open() { if(quit_safeguard(false)) { Gtk::FileChooserDialog fd("Open notebook...", Gtk::FILE_CHOOSER_ACTION_OPEN); fd.add_button(Gtk::Stock::OPEN,1); fd.add_button(Gtk::Stock::CANCEL,2); fd.set_default_response(1); int action=fd.run(); if(action==1) { fd.hide_all(); std::string res=load(fd.get_filename()); if(res.size()>0) { Gtk::MessageDialog md("Error loading document "+fd.get_filename()); md.set_secondary_text(res); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); // md.set_position(Gtk::WIN_POS_CENTER_ALWAYS); md.run(); } else { name=fd.get_filename(); Glib::RefPtr newcell(new DataCell(DataCell::c_input)); add_cell(newcell, Glib::RefPtr() ); show_cell(newcell); active_canvas->select_first_input_cell(); modified=false; update_title(); } } } } void XCadabra::on_file_save() { // check if name known, otherwise call save_as if(name.size()>0) { std::string res=save(name); if(res.size()>0) { Gtk::MessageDialog md("Error saving document "+name); md.set_secondary_text(res); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); // md.set_position(Gtk::WIN_POS_CENTER_ALWAYS); md.run(); } else { modified=false; update_title(); } } else on_file_save_as(); } void XCadabra::on_file_export_text() { Gtk::FileChooserDialog fd("Export to text...", Gtk::FILE_CHOOSER_ACTION_SAVE); fd.add_button(Gtk::Stock::SAVE,1); fd.add_button(Gtk::Stock::CANCEL,2); int action=fd.run(); if(action==1) { fd.hide_all(); #ifdef DEBUG std::cerr << "going to export as " << fd.get_filename() << std::endl; #endif std::string res=expo(fd.get_filename()); if(res.size()>0) { Gtk::MessageDialog md("Error exporting document "+fd.get_filename()); md.set_secondary_text(res); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); // md.set_position(Gtk::WIN_POS_CENTER_ALWAYS); md.run(); } } } void XCadabra::update_title() { if(name.size()>0) { if(modified) set_title("XCadabra: "+name+"*"); else set_title("XCadabra: "+name); } else { if(modified) set_title("XCadabra*"); else set_title("XCadabra"); } } void XCadabra::on_file_save_as() { for(;;) { Gtk::FileChooserDialog fd("Save notebook as...", Gtk::FILE_CHOOSER_ACTION_SAVE); fd.add_button(Gtk::Stock::SAVE,1); fd.add_button(Gtk::Stock::CANCEL,2); fd.set_default_response(1); int action=fd.run(); if(action==1) { fd.hide_all(); std::ifstream testpresence(fd.get_filename().c_str()); if(testpresence.is_open()) { Gtk::MessageDialog md("File "+fd.get_filename()+" already exists.", false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE, true); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); md.add_button("Overwrite",1); md.add_button("Choose other name",2); if(md.run()!=1) continue; } std::string res=save(fd.get_filename()); if(res.size()>0) { Gtk::MessageDialog md("Error saving document "+fd.get_filename()); md.set_secondary_text(res); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); md.run(); } else { name=fd.get_filename(); modified=false; update_title(); } } break; } } void XCadabra::on_file_print() { Gtk::MessageDialog md("Printing information"); md.set_secondary_text("In order to print a notebook file, simply save it and then run LaTeX on it.\n\nCadabra notebook files are at the same time also valid LaTeX files, ready to be processed in any way you would normally process LaTeX files."); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); // md.set_position(Gtk::WIN_POS_CENTER_ALWAYS); md.run(); } void XCadabra::clear() { // Remove all NotebookCanvas objects by removing the // outer-most one. mainbox.remove(*canvasses[0]); canvasses.clear(); // Remove all DataCells (the RefPtrs handle cleaning up of the cells themselves). datacells.clear(); // Add in a new NotebookCanvas canvasses.push_back(manage( new NotebookCanvas(*this) )); mainbox.pack_start(*canvasses.back(), Gtk::PACK_EXPAND_WIDGET, 0); active_canvas=canvasses.back(); active_cell=0; selected=0; // canvasses.back()->to_cdb.connect(sigc::mem_fun(*this, &XCadabra::handle_editbox_output)); show_all(); name=""; modified=false; update_title(); } // Returns false if backup could not be made. // Returns true if original file not present or backup ok. bool XCadabra::make_backup(const std::string& nm) const { std::ifstream old(nm.c_str()); std::ofstream temp(std::string(nm+"~").c_str()); if(!old) return true; if(temp) { std::string ln; while(std::getline(old, ln)) { temp << ln << "\n"; if(!temp) return false; } return true; } return false; } std::string XCadabra::save(const std::string& fn) const { if(!make_backup(fn)) return "Cannot create backup file."; std::ofstream str(fn.c_str()); if(!str) { return "Cannot open file for writing."; } else { str << "% Cadabra notebook version 1.2\n" << "\\documentclass[11pt]{article}\n" << "\\usepackage[textwidth=460pt, textheight=660pt]{geometry}\n" << "\\usepackage[usenames,dvipsnames]{color}\n" << "\\usepackage{amssymb}\n" << "\\usepackage[parfill]{parskip}\n" << "\\usepackage{breqn}\n" << "\\usepackage{tableaux}\n" << "\\def\\specialcolon{\\mathrel{\\mathop{:}}\\hspace{-.5em}}\n" << "\\renewcommand{\\bar}[1]{\\overline{#1}}\n" << "\\begin{document}\n"; DataCells_t::const_iterator it=datacells.begin(); while(it!=datacells.end()) { if((*it)->textbuf->size()>0) { switch((*it)->cell_type) { case DataCell::c_input: str << "{\\color[named]{Blue}\\begin{verbatim}\n" << trim( (*it)->textbuf->get_text() ) << "\n\\end{verbatim}}\n"; break; case DataCell::c_output: str << "% orig\n"; str << "% " << (*it)->cdbbuf << "\n"; str << "% end_orig\n"; str << "\\begin{dmath*}[compact, spread=2pt]\n" << trim( (*it)->textbuf->get_text() ) << "\n\\end{dmath*}\n"; break; case DataCell::c_comment: str << "\\begin{verbatim}\n" << trim( (*it)->textbuf->get_text() ) << "\n\\end{verbatim}\n"; break; case DataCell::c_texcomment: str << "% Begin TeX comment\n" << trim( (*it)->textbuf->get_text() ) << "\n% End TeX comment\n"; break; case DataCell::c_tex: str << "% Begin TeX cell " << ( (*it)->tex_hidden==true ? "closed\n":"open\n" ); if((*it)->sectioning>0) str << "\\section{" << trim( (*it)->textbuf->get_text() ) << "}"; else str << trim( (*it)->textbuf->get_text() ); str << "\n% End TeX cell\n"; break; case DataCell::c_error: str << "{\\color[named]{Red}%\n" << trim( (*it)->textbuf->get_text() ) << "%\n" << "} % error\n"; break; } } ++it; } str << "\\end{document}\n"; } return ""; } std::string XCadabra::expo(const std::string& fn) const { if(!make_backup(fn)) return "Cannot create backup file."; std::ofstream str(fn.c_str()); if(!str) { return "Cannot open file for writing."; } else { str << "# Exported Cadabra notebook\n"; DataCells_t::const_iterator it=datacells.begin(); while(it!=datacells.end()) { if((*it)->textbuf->size()>0) { switch((*it)->cell_type) { case DataCell::c_input: str << trim( (*it)->textbuf->get_text() ) << "\n\n"; break; case DataCell::c_tex: // str << "% Begin TeX cell " // << ( (*it)->tex_hidden==true ? "closed\n":"open\n" ); // if((*it)->sectioning>0) // str << "\\section{" << trim( (*it)->textbuf->get_text() ) << "}"; // else str << trim( (*it)->textbuf->get_text() ); // str << "\n% End TeX cell\n"; break; case DataCell::c_error: case DataCell::c_output: case DataCell::c_comment: case DataCell::c_texcomment: break; break; } } ++it; } str << "\n"; } return ""; } std::string XCadabra::load(const std::string& fn, bool ignore_nonexistence) { struct stat buf; int statres=lstat(fn.c_str(), &buf); if(statres==-1) { switch(errno) { case EACCES: return "Search permission denied."; case ELOOP: return "Too many symbolic links."; case ENOENT: if(ignore_nonexistence) { clear(); return ""; } else return "File does not exist."; default: return "Error stat'ing file."; } } std::ifstream str(fn.c_str()); std::ostringstream err; if(str.is_open()==false) { return "Read permission denied."; } else { std::string ln; std::getline(str,ln); if(ln.substr(0,30)!="% Cadabra notebook version 1.0") { if(ln.substr(0,30)!="% Cadabra notebook version 1.1") { if(ln.substr(0,30)!="% Cadabra notebook version 1.2") { return "Not in Cadabra notebook version <= 1.2 format."; } } } clear(); enum state_t { s_top, s_input, s_output, s_comment, s_texcomment, s_tex, s_error, s_output_as_cdb }; state_t curstat=s_top; std::string buffer, cdb_buffer; int line_num=2; bool tex_hidden=false; b_cdbstatus.set_text(" Status: Loading notebook..."); get_window()->set_cursor(hglass); while(std::getline(str,ln)) { #ifdef DEBUG std::cerr << "read: " << ln << std::endl; #endif if(ln=="{\\color[named]{Blue}\\begin{verbatim}") { if(curstat!=s_top) { err << "Illegal location of input cell at line " << line_num << "."; kernel_idle(); return err.str(); } curstat=s_input; buffer=""; } else if(ln=="\\end{verbatim}}") { if(curstat!=s_input) { err << "Unmatched input cell closing at line " << line_num << "."; kernel_idle(); return err.str(); } Glib::RefPtr newcell(new DataCell(DataCell::c_input, buffer)); add_cell(newcell, Glib::RefPtr()); curstat=s_top; } else if(ln=="{\\color[named]{Red}%") { if(curstat!=s_top) { err << "Illegal location of error cell at line " << line_num << "."; kernel_idle(); return err.str(); } curstat=s_error; buffer=""; } else if(ln=="} % error") { if(curstat!=s_error) { err << "Unmatched error cell closing at line " << line_num << "."; kernel_idle(); return err.str(); } Glib::RefPtr newcell(new DataCell(DataCell::c_error, buffer)); add_cell(newcell, Glib::RefPtr()); curstat=s_top; } else if(ln.substr(0,6)=="% orig") { if(curstat!=s_top) { err << "Illegal location of output cell in Cadabra input format at line " << line_num << "."; kernel_idle(); return err.str(); } curstat=s_output_as_cdb; buffer=""; cdb_buffer=""; } else if(ln.substr(0,10)=="% end_orig") { if(curstat!=s_output_as_cdb) { err << "Unmatched output cell in Cadabra input format closing at line " << line_num << "."; kernel_idle(); return err.str(); } curstat=s_top; cdb_buffer=buffer; buffer=""; } else if(ln.substr(0,14)=="\\begin{dmath*}") { if(curstat!=s_top) { err << "Illegal location of output cell at line " << line_num << "."; kernel_idle(); return err.str(); } curstat=s_output; buffer=""; } else if(ln=="\\end{dmath*}") { if(curstat!=s_output) { err << "Unmatched output cell closing at line " << line_num << "."; kernel_idle(); return err.str(); } #ifdef DEBUG std::cerr << buffer << std::endl; #endif Glib::RefPtr newcell(new DataCell(DataCell::c_output, buffer)); if(cdb_buffer.size()>2) newcell->cdbbuf=cdb_buffer.substr(2); cdb_buffer=""; add_cell(newcell, Glib::RefPtr()); curstat=s_top; } else if(ln=="\\begin{verbatim}") { if(curstat!=s_top) { err << "Illegal location of comment cell at line " << line_num << "."; kernel_idle(); return err.str(); } curstat=s_comment; buffer=""; } else if(ln=="\\end{verbatim}") { if(curstat!=s_comment) { err << "Unmatched comment cell closing at line " << line_num << "."; kernel_idle(); return err.str(); } Glib::RefPtr newcell(new DataCell(DataCell::c_comment, buffer)); add_cell(newcell, Glib::RefPtr()); curstat=s_top; } else if(ln=="% Begin TeX comment") { if(curstat!=s_top) { err << "Illegal location of TeX comment cell at line " << line_num << "."; kernel_idle(); return err.str(); } curstat=s_texcomment; buffer=""; } else if(ln=="% End TeX comment") { if(curstat!=s_texcomment) { err << "Unmatched TeX comment cell closing at line " << line_num << "."; kernel_idle(); return err.str(); } Glib::RefPtr newcell(new DataCell(DataCell::c_texcomment, buffer)); add_cell(newcell, Glib::RefPtr()); curstat=s_top; } else if(ln=="% Begin TeX cell open") { if(curstat!=s_top) { err << "Illegal location of TeX cell at line " << line_num << "."; kernel_idle(); return err.str(); } curstat=s_tex; tex_hidden=false; buffer=""; } else if(ln=="% Begin TeX cell closed") { if(curstat!=s_top) { err << "Illegal location of TeX cell at line " << line_num << "."; kernel_idle(); return err.str(); } curstat=s_tex; tex_hidden=true; buffer=""; } else if(ln=="% End TeX cell") { if(curstat!=s_tex) { err << "Unmatched TeX cell closing at line " << line_num << "."; kernel_idle(); return err.str(); } Glib::RefPtr newcell(new DataCell(DataCell::c_tex, trim(buffer))); newcell->tex_hidden=tex_hidden; add_cell(newcell, Glib::RefPtr()); curstat=s_top; } else buffer+=ln+"\n"; ++line_num; } } // Now generate all TeX output and then show all widgets. try { tex_engine_main.convert_all(); } catch(TeXEngine::TeXException& ex) { generic_error_popup(std::string(ex.what())); } show_all(); // while (gtk_events_pending ()) // gtk_main_iteration (); // active_canvas->select_first_input_cell(); kernel_idle(); return ""; } void XCadabra::on_file_quit() { if(quit_safeguard()) { // cdb.terminate(); // Ensure that the kernel is really gone, not just stuck in an infinite loop. if(cdb.get_pid()!=0) if(kill(cdb.get_pid(), 0)==0) kill(cdb.get_pid(), SIGKILL); Gtk::Main::quit(); } } bool XCadabra::quit_safeguard(bool quit) { if(modified) { std::string mes; if(quit) { if(name.size()>0) mes="Save changes to "+name+" before closing?"; else mes="Save changes before closing?"; } else { if(name.size()>0) mes="Save changes to "+name+" before continuing?"; else mes="Save changes before continuing?"; } Gtk::MessageDialog md(mes, false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE, true); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); md.add_button(Gtk::Stock::SAVE,1); md.add_button(Gtk::Stock::CANCEL,2); if(quit) md.add_button(Gtk::Stock::QUIT,3); else md.add_button(Gtk::Stock::NO, 3); int action=md.run(); switch(action) { case 1: on_file_save(); return true; case 2: break; case 3: return true; } } else return true; return false; } void XCadabra::on_edit_copy() { } void XCadabra::on_edit_paste() { } void XCadabra::on_edit_insert_tex_above() { Glib::RefPtr newcell(new DataCell(DataCell::c_tex, "[empty TeX cell]")); action_add(Glib::RefPtr(new ActionAddCell(newcell, active_cell->datacell, true))); show_cell(newcell); // while (gtk_events_pending ()) // gtk_main_iteration (); active_canvas->cell_grab_focus(newcell); set_next_into_view(active_cell); // active_canvas->scroll_into_view(newcell); } void XCadabra::on_edit_insert_tex_below() { Glib::RefPtr newcell(new DataCell(DataCell::c_tex, "[empty TeX cell]")); action_add(Glib::RefPtr(new ActionAddCell(newcell, active_cell->datacell, false))); show_cell(newcell); // while (gtk_events_pending ()) // gtk_main_iteration (); active_canvas->cell_grab_focus(newcell); set_next_into_view(active_cell); // active_canvas->scroll_into_view(newcell); } void XCadabra::on_edit_insert_input_above() { Glib::RefPtr newcell(new DataCell(DataCell::c_input, "")); action_add(Glib::RefPtr(new ActionAddCell(newcell, active_cell->datacell, true))); show_cell(newcell); // while (gtk_events_pending ()) // gtk_main_iteration (); active_canvas->cell_grab_focus(newcell); set_next_into_view(active_cell); // active_canvas->scroll_into_view(newcell); } void XCadabra::on_edit_insert_input_below() { Glib::RefPtr newcell(new DataCell(DataCell::c_input, "")); action_add(Glib::RefPtr(new ActionAddCell(newcell, active_cell->datacell, false))); show_cell(newcell); // while (gtk_events_pending ()) // gtk_main_iteration (); active_canvas->cell_grab_focus(newcell); set_next_into_view(active_cell); // active_canvas->scroll_into_view(newcell); } void XCadabra::on_edit_insert_section_above() { Glib::RefPtr newcell(new DataCell(DataCell::c_tex, "[insert section header]")); show_cell(newcell); newcell->sectioning=1; active_canvas->cell_grab_focus( add_cell(newcell, active_cell->datacell) ); // HERE } void XCadabra::on_edit_remove_cell() { Glib::RefPtr dc=active_cell->datacell; // Prevent removal of the first cell of the notebook. if(std::find(datacells.begin(), datacells.end(), dc)==datacells.begin()) return; if(dc->cell_type!=DataCell::c_input && dc->cell_type!=DataCell::c_tex) return; action_add(Glib::RefPtr(new ActionRemoveCell(dc))); } void XCadabra::on_edit_divide_cell() { Glib::RefPtr dc=active_cell->datacell; if(dc->cell_type!=DataCell::c_input) return; selected=0; DataCells_t::iterator fnd=std::find(datacells.begin(), datacells.end(), dc); if(fnd==datacells.end()) return; #ifdef DEBUG std::cerr << "dividing cell" << std::endl; #endif // Find the position of the cursor. std::string segment1= trim( dc->textbuf->get_slice(dc->textbuf->begin(), dc->textbuf->get_iter_at_mark(dc->textbuf->get_insert()))); std::string segment2= trim( dc->textbuf->get_slice(dc->textbuf->get_iter_at_mark(dc->textbuf->get_insert()), dc->textbuf->end())); if(segment1.size()==0 || segment2.size()==0) return; remove_noninput_below(dc); dc->textbuf->erase(dc->textbuf->get_iter_at_mark(dc->textbuf->get_insert()), dc->textbuf->end()); Glib::RefPtr newcell(new DataCell(DataCell::c_input, segment2)); action_add(Glib::RefPtr(new ActionAddCell(newcell, dc, false))); show_cell(newcell); } void XCadabra::on_view_split() { add_canvas(); } void XCadabra::on_view_close() { if(canvasses.size()>1) { canvasses[canvasses.size()-2]->remove(*canvasses.back()); canvasses.pop_back(); } } void XCadabra::on_settings_font_size(int num) { if(font_step==num) return; font_step=num; std::string res=save_config(); if(res.size()>0) { Gtk::MessageDialog md("Error"); md.set_secondary_text(res); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); md.run(); } // Update all TeXBuffers, i.e. rerun tex & dvipng on them. DataCells_t::iterator it=datacells.begin(); while(it!=datacells.end()) { if((*it)->cell_type==DataCell::c_output || (*it)->cell_type==DataCell::c_tex || (*it)->cell_type==DataCell::c_error || (*it)->cell_type==DataCell::c_comment || (*it)->cell_type==DataCell::c_texcomment) { tex_engine_main.set_font_size(12+(num*2)); (*it)->texbuf->regenerate(); } ++it; } // Update all VisualCells. try { tex_engine_main.convert_all(); } catch(TeXEngine::TeXException& ex) { generic_error_popup(std::string(ex.what())); } for(unsigned int i=0; iredraw_cells(); } void XCadabra::on_settings_brain(int num) { if(brain_wired==num) return; brain_wired=num; std::string res=save_config(); if(res.size()>0) { Gtk::MessageDialog md("Error"); md.set_secondary_text(res); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); md.run(); } } void XCadabra::on_tutorial_open(unsigned int num) { Gtk::MessageDialog md("Tutorial information"); md.set_secondary_text("Tutorials are not yet available, sorry."); md.set_type_hint(Gdk::WINDOW_TYPE_HINT_DIALOG); md.run(); } void XCadabra::on_clipboard_get(Gtk::SelectionData& selection_data, guint info) { const Glib::ustring target = selection_data.get_target(); if(target == "cadabra") selection_data.set("cadabra", clipboard_cdb); else if(target == "UTF8_STRING" || target=="TEXT") { selection_data.set_text(clipboard_txt); } } void XCadabra::on_clipboard_clear() { } void XCadabra::set_next_into_view(VisualCell *vc) { to_scroll_to=vc; // Activate the on_idle handler so that we can handle this request. Glib::signal_idle().connect( sigc::mem_fun(*this, &XCadabra::on_idle) ); } bool XCadabra::on_idle() { if(active_canvas!=0) { if(to_scroll_to!=0) { active_canvas->scroll_into_view(to_scroll_to, false); to_scroll_to=0; } } return false; } std::string XCadabra::save_config() const { std::string defname=getenv("HOME"); defname+="/.xcadabra"; std::ofstream conf(defname.c_str(), std::ofstream::out); if(conf.fail()) return "Cannot open ~/.xcadabra for writing."; conf << "# XCadabra configuration file version 1.0" << std::endl; conf << "font_step:=" << font_step << std::endl; conf << "brain_wired:=" << brain_wired << std::endl; conf.close(); return ""; } std::string XCadabra::load_config() { std::string defname=getenv("HOME"); defname+="/.xcadabra"; std::ifstream conf(defname.c_str()); std::ostringstream str; std::string rl; int line=1; if(conf.is_open()) { while(getline(conf, rl)) { if(rl.size()>0 && rl[0]=='#') continue; size_t pos=rl.find(":="); if(pos==std::string::npos) { str << "Error parsing ~/.xcadabra on line " << line << std::endl; return str.str(); } if(rl.substr(0,pos)=="font_step") { int tmp=atoi(rl.substr(pos+2).c_str()); if(tmp<-2 || tmp>10) { str << "Out-of-bounds value for " << rl.substr(0,pos) << " in ~/.xcadabra on line " << line << std::endl; return str.str(); } font_step=tmp; } else if(rl.substr(0,pos)=="brain_wired") { int tmp=atoi(rl.substr(pos+2).c_str()); if(tmp<0 || tmp>1) { str << "Out-of-bounds value for " << rl.substr(0,pos) << " in ~/.xcadabra on line " << line << std::endl; return str.str(); } brain_wired=tmp; } else { str << "Unknown identifier " << rl.substr(0,pos) << " in ~/.xcadabra line " << line << std::endl; return str.str(); } ++line; } } return ""; } std::string CadabraHelp::texify(const std::string& str) const { std::string res; for(unsigned int i=0; iadd( Gtk::Action::create(property, duplicate_underscores(property)), sigc::bind( sigc::mem_fun(*this, &XCadabra::on_help_properties), property) ); uimanager->add_ui_from_string(""); property_set.insert(property.substr(2)); } void XCadabra::add_algorithm_help(const std::string& algorithm) { actiongroup->add( Gtk::Action::create(algorithm, duplicate_underscores(algorithm)), sigc::bind( sigc::mem_fun(*this, &XCadabra::on_help_algorithms), algorithm) ); uimanager->add_ui_from_string(""); algorithm_set.insert(algorithm.substr(1)); } void XCadabra::add_reserved_help(const std::string& reserved) { actiongroup->add( Gtk::Action::create(reserved, duplicate_underscores(reserved)), sigc::bind( sigc::mem_fun(*this, &XCadabra::on_help_reserved), reserved) ); uimanager->add_ui_from_string(""); } cadabra-1.39/gui/window.hh000066400000000000000000000400411234107666300154460ustar00rootroot00000000000000/* Cadabra: a field-theory motivated computer algebra system. Copyright (C) 2001-2011 Kasper Peeters 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 3 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, see . */ #ifndef window_hh__ #define window_hh__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "widgets.hh" #include "help.hh" class XCadabra; /// A DataCell contains the information required to display a /// cell, but not the actual widget. Therefore, multiple widgets /// can read from the data stored in this cell; multiple notebook /// canvasses can therefore display the same notebook data. /// /// DataCells are stored on the heap and reference counted since there /// are too many objects with a pointer to them to keep track of /// proper de-allocation manually. class DataCell : public Glib::Object { public: enum cell_t { c_input, c_output, c_comment, c_texcomment, c_tex, c_error }; DataCell(cell_t, const std::string& str="", bool texhidden=false); cell_t cell_type; Glib::RefPtr textbuf; Glib::RefPtr texbuf; std::string cdbbuf; // c_output only: the output in cadabra input format bool tex_hidden; // c_tex only bool sensitive; int sectioning; // >0 for section header cells bool running; }; /// A VisualCell contains pointers to the various cell widgets, /// which in turn contain pointers to DataCell objects. class VisualCell { public: union { ExpressionInput *inbox; TeXView *outbox; TeXInput *texbox; }; Glib::RefPtr datacell; }; /// The Action object is used to pass user action instructions around /// and store them in the undo/redo stacks. All references to cells is /// in terms of smart pointers to DataCells. /// /// This requires that if we delete a cell, its data cell together /// with any TextBuffer and TeXBuffer objects should be kept in /// memory, so that the pointer remains valid. We keep a RefPtr. class ActionBase : public Glib::Object { public: ActionBase(Glib::RefPtr); virtual void execute(XCadabra&)=0; virtual void revert(XCadabra&)=0; Glib::RefPtr cell; }; /// As a general rule, objects derived from ActionBase are friends of XCadabra, /// so they really should be thought of as bits of functionality split off from /// that large class. class ActionAddCell : public ActionBase { public: ActionAddCell(Glib::RefPtr, Glib::RefPtr ref_, bool before_); /// Executing will also show the cell and grab its focus. virtual void execute(XCadabra&); virtual void revert(XCadabra&); private: // Keep track of the location where this cell is inserted into // the notebook. Glib::RefPtr ref; bool before; std::vector > associated_cells; // output and comment cells }; class ActionRemoveCell : public ActionBase { public: ActionRemoveCell(Glib::RefPtr); ~ActionRemoveCell(); virtual void execute(XCadabra&); virtual void revert(XCadabra&); private: // Keep track of the location where this cell was in the notebook. Since it is // not possible to delete the first cell, it is safe to keep a reference to the // cell just before the one we are deleting. // Note that since we keep a RefPtr to this datacell, that cell will stay alive // even when a subsequent action will remove it. Glib::RefPtr prev_cell; std::vector > associated_cells; // output and comment cells }; class ActionAddText : public ActionBase { public: ActionAddText(Glib::RefPtr, int, const std::string&); virtual void execute(XCadabra&); virtual void revert(XCadabra&); int insert_pos; std::string text; }; class ActionRemoveText : public ActionBase { public: ActionRemoveText(Glib::RefPtr, int, int, const std::string&); virtual void execute(XCadabra&); virtual void revert(XCadabra&); int from_pos, to_pos; std::string removed_text; }; typedef std::stack > ActionStack; /// NotebookCanvas is a view on notebook data. Any number of these /// may be instantiated, and they all reflect the current status /// of the document stored in the master XCadabra class. class NotebookCanvas : public Gtk::VPaned { public: NotebookCanvas(XCadabra& doc); ~NotebookCanvas(); // bool handle_expression_input(std::string str); // bool handle_tex_update(const std::string&); // bool receive_output(std::string eqno, std::string eq); // bool receive_comment(std::string comment); bool handle_key_press_event(GdkEventKey*); /// Add a VisualCell corresponding to the given DataCell. /// The second and third element determine the position relative /// to another DataCell (or, by default, relative to the end marker). VisualCell* add_cell(Glib::RefPtr, Glib::RefPtr ref, bool before=true); void show_cell(Glib::RefPtr); /// Remove a VisualCell corresponding to the given DataCell. void remove_cell(Glib::RefPtr); /// Make a cell grab focus. This will trigger a run of this cell, with various /// other side-effects before it returns. void cell_grab_focus(VisualCell *); void cell_grab_focus(Glib::RefPtr); void select_first_input_cell(); virtual void show(); // void scroll_to(Gtk::Allocation al); void redraw_cells(); bool scroll_into_view_callback(VisualCell *); bool scroll_into_view(VisualCell *, bool center=false); bool scroll_into_view(Glib::RefPtr, bool center=false); void scroll_to_start(); void scroll_to_end(); void scroll_up(); void scroll_down(); XCadabra& doc; typedef std::list VisualCells_t; VisualCells_t visualcells; // managed here Gtk::EventBox ebox; Gtk::ScrolledWindow scroll; Gtk::VBox scrollbox; Gtk::HSeparator bottomline; }; /// Each notebook has one cadabra process associated to it, and one /// main window to control it. class XCadabra : public Gtk::Window { public: XCadabra(modglue::ext_process&, const std::string& filename, modglue::main *); virtual ~XCadabra(); /// Data coming from cadabra arrives here. This handles /// adding boxes to the document and propagating this to the /// notebooks. bool receive(modglue::ipipe& p); bool receive_err(modglue::ipipe& p); std::string accumulated_error; /// Data from the NotebookCanvas objects arrives here. bool handle_editbox_output(std::string str, NotebookCanvas *, VisualCell *); void on_my_insert(const Gtk::TextIter& pos, const Glib::ustring& text, int bytes, Glib::RefPtr); void on_my_erase(const Gtk::TextIter& start, const Gtk::TextIter& end, Glib::RefPtr); /// Events from the notebook cells arrive here. void handle_on_grab_focus(NotebookCanvas *, VisualCell *); bool handle_visibility_toggle(GdkEventButton *, NotebookCanvas *, VisualCell *); bool handle_outbox_select(GdkEventButton *, NotebookCanvas *, VisualCell *); bool handle_tex_update_request(std::string, NotebookCanvas *, VisualCell *); /// Toplevel keyboard handling. virtual bool on_key_press_event(GdkEventKey *); /// All the menu routines. void on_file_new(); void on_file_open(); void on_file_save(); void on_file_save_as(); void on_file_print(); void on_file_export_text(); void on_file_quit(); bool quit_safeguard(bool quit=true); void on_edit_copy(); void on_edit_paste(); void on_edit_insert_tex_above(); void on_edit_insert_tex_below(); void on_edit_insert_input_above(); void on_edit_insert_input_below(); void on_edit_insert_section_above(); void on_edit_remove_cell(); void on_edit_divide_cell(); void on_view_split(); void on_view_close(); void on_settings_font_size(int); void on_settings_brain(int); void on_tutorial_open(unsigned int); void on_help_about(); void on_help_citing(); void on_help_properties(const std::string&); void on_help_algorithms(const std::string&); void on_help_reserved(const std::string&); bool on_autocomplete(); void on_help_context(); void on_stop(); void on_kill(); void on_run(); void on_run_to(); void on_run_from(); bool current_objtype_and_name(CadabraHelp::objtype_t&, std::string&); void insert_at_mark(const std::string instxt); /// Saving and loading to/from disk. If the return string is /// non-empty, it contains an error message. void clear(); std::string save(const std::string&) const; std::string load(const std::string&, bool ignore_nonexistence=false); std::string expo(const std::string&) const; /// Handling starting/restarting of the kernel. bool on_kernel_exit(modglue::ext_process&); /// Clipboard handling void on_clipboard_get(Gtk::SelectionData&, guint info); void on_clipboard_clear(); std::string clipboard_txt, clipboard_cdb; /// Adding and removing cells from the current document. /// These routines also update all NotebookCanvas objects /// so that they reflect the current structure of the document. /// The DataCell ownership is handled by the XCadabra class once /// it has been added here. /// These functions do _not_ grab focus or make the new cell active. /// The add_cell member also does _not_ call show_cell: cells will not /// automatically become visible. Glib::RefPtr add_cell(Glib::RefPtr, Glib::RefPtr ref, bool before=true); /// Show the datacell in all canvasses. void show_cell(Glib::RefPtr); /// Add another notebook canvas to the window. void add_canvas(); /// Call this to determine which cell will scroll into view as soon as the Gtk main loop /// regains control. void set_next_into_view(VisualCell *); /// Signals from Gtk, such as closing windows or changing the text /// of an input cell. virtual bool on_delete_event(GdkEventAny*); virtual bool on_configure_event(GdkEventConfigure*); void on_signal_exception(); void input_cell_modified(); void tex_cell_modified(); /// Display of error messages. void generic_error_popup(const std::string&) const; void connect_io_signals(); void disconnect_io_signals(); int font_step; int brain_wired; private: /// Variables for the undo/redo mechanism. ActionStack undo_stack, redo_stack; bool disable_stacks; // for changes which should not be recorded on the stack bool action_add(Glib::RefPtr); // takes ownership and fills the stacks void action_undo(); void action_redo(); /// Various assorted other variables related to communicating with the kernel. Gdk::Cursor hglass; bool load_file; // used by main to indicate a load should occur after start bool have_received; modglue::main *cmm; std::map connections; std::string name; bool modified; bool running; Glib::RefPtr running_last; bool restarting_kernel; bool callmm(Glib::IOCondition, int fd); void update_title(); bool make_backup(const std::string&) const; void remove_noninput_below(Glib::RefPtr); void kernel_idle(); /// A map to keep track of identifiers of input cells. These are used to associated input /// data to the kernel to output data from the kernel, and hence can be used to associate /// the output to the right input cell. std::map > id_to_datacell; long last_used_id; /// Boxes and widgets. std::vector canvasses; // managed by gtk CadabraHelp help_window; NotebookCanvas *active_canvas; VisualCell *active_cell; Gtk::VBox topbox; Gtk::HBox supermainbox; Gtk::VBox mainbox; Gtk::HBox buttonbox; Gtk::HBox statusbarbox; Gtk::VBox progressbarvbox; Gtk::ProgressBar progressbar1,progressbar2; Glib::RefPtr actiongroup; Glib::RefPtr undo_action_menu, redo_action_menu; Glib::RefPtr uimanager; Glib::RefPtr font_action0, font_action1, font_action2, font_action3; Glib::RefPtr brain_wired_action0, brain_wired_action1; Gtk::HBox statusbox; Gtk::Label b_cdbstatus, b_kernelversion; Gtk::Button b_kill, b_run, b_run_to, b_run_from, b_help, b_stop, b_undo, b_redo; int last_configure_width; /// Storage of document data. This data is not managed by smart /// pointers and should thus be deleted by the XCadabra /// destructor. /// The order in which pointers to datacells appear reflects the /// order in the document. We never use iterators directly in this /// list to refer to a cell (always use the RefPtr pointers). typedef std::list > DataCells_t; DataCells_t datacells; /// Data concerning the interaction with the externally started /// cadabra process. modglue::ext_process& cdb; enum parse_mode_t { m_status, m_eqno, m_eq, m_property, m_algorithm, m_reserved, m_discard, m_comment, m_texcomment, m_error, m_progress, m_plain }; std::vector parse_mode; std::string eqno, eq, status, progress, plain, algorithm, property, reserved; int progress_todo, progress_done, progress_count; /// Collection of all known algorithm and property names, as extracted from the kernel. void add_property_help(const std::string&); void add_algorithm_help(const std::string&); void add_reserved_help(const std::string&); std::set property_set, algorithm_set; static const char * const autocomplete_strings[]; std::string duplicate_underscores(const std::string& str) const; /// Cut-n-paste data VisualCell *selected; /// Configuration data saving/loading std::string save_config() const; std::string load_config(); TeXEngine tex_engine; friend class ActionRemoveCell; friend class ActionAddCell; /// When the main loop is idle, this function will get called and will check /// all 'to_scroll_to' cells of the canvasses. bool on_idle(); /// Cell to scroll into view as soon as the main loop is idle. VisualCell *to_scroll_to; }; #endif cadabra-1.39/html/000077500000000000000000000000001234107666300137775ustar00rootroot00000000000000cadabra-1.39/html/component-cadabra.html000066400000000000000000000475231234107666300202550ustar00rootroot00000000000000 Component cadabra

cadabra component: cadabra

All issues

2010-06-17 @fierz does not work when there are no gamma matrices
2010-05-19 Add proper pattern handling to LaTeXForm
2010-05-18 Accents mess up @canonicalise
2010-05-16 Pasting from PDF can introduce spurious ctrl-M
2010-04-06 Powers do not parse correctly
fixed 2010-02-27 @sym/@asym duplicate symbols in tree symmetrisation
2010-02-08 Superfluous square brackets with [..] action
2010-02-08 TableauSymmetry assigned to a list fails.
2010-02-08 Repeated divisions are buggy
2010-02-07 Kernel hang
2010-02-06 Eliminate metric acts on non-tensors.
fixed 2010-02-05 Worldsheet susy sample is broken
2010-02-02 Eliminating metrics with position-free indices fails.
fixed 2010-01-31 @collect_factors does not take commutativity properties into account 1.18
2010-01-30 Conversion of / to \frac misplaces bracket types.
2009-11-18 Numerical indices default to position=free.
2009-11-18 Fix dependence on numbers
fixed 2009-11-16 Deleting last cell of notebook sometimes produces warnings 1.18
fixed 2009-11-16 Printing problem with \commutator 1.17
won't fix 2009-11-14 Depends property overwrites earlier ones. 1.17
fixed 2009-11-14 Varying does not handle single-factor terms. 1.17
fixed 2009-11-14 Expanding fractional powers fails. 1.17
fixed 2009-11-14 Accented tensors fail to print 1.17
fixed 2009-09-02 Derivatives of sums do not always display correctly in notebook 1.17
2009-08-23 Implicit indices need to come in normal and conjugate forms.
2009-08-23 @fierz does not produce useful error messages.
2009-08-21 Redraw segfault on OS X
2009-08-20 @factor_out does not handle powers
2009-08-20 @factor_out does not take into account commutativity properties
2009-08-18 'Derivation' property
2009-07-24 Single-object factors with brackets do not print correctly
2009-06-30 Cleanup output routines
2009-06-29 Make @canonicalise work on functional arguments
fixed 2009-06-29 Re-LaTeX TeX cells on close
2009-06-27 Fix output messages to be TeX
2009-06-27 Bracket flexibility leads to inconsistencies
2009-06-26 Handle PartialDerivatives with no arguments
fixed 2009-06-26 Dividing active cell does not work anymore
2009-06-19 Potential bug with A_{m m} -> replacements
fixed 2009-06-03 Automatic index raising/lowering not handled in @canonicalise
2009-05-26 Unify handling of commutation signs
in progress 2009-05-26 Inherit<...> is not flexible enough
fixed 2009-01-19 Crash with tensors in numerators
2009-01-03 @canonicalise does not honor ImplicitIndex
2008-12-11 Introduce a notation for 'a range of objects'
fixed 2008-11-24 Nested \partial's do not always flatten automatically.
fixed 2008-11-17 Single-factor replacements with dummy names fail.
fixed 2008-11-14 @eliminate_kr does not work on sums
fixed 2008-11-14 XCadabra breaks when a .cadabra is present
2008-08-29 Add support for differential 'd'
fixed 2008-08-25 Ask user before overwriting existing files.
2008-08-24 Cursor position after crash
2008-08-24 @factor_out problems with tensors
fixed 2008-08-24 Multiple-level undo in GUI
cadabra-1.39/html/index.html000066400000000000000000000116011234107666300157730ustar00rootroot00000000000000 cadabra Issue Tracker

cadabra Issue Tracker

Upcoming Releases

1.21 no issues

Past Releases

1.18on 2010-02-06
1.17on 2010-01-28
1.15on 2009-08-18
1.12on 2009-08-18
1.05on 2009-06-03
1.0on 2008-12-11
0.144on 2008-08-29

Unassigned issues

46 unassigned issues (34 open).

Recent activity

2010-06-17 @fierz does not work when there are no gamma matrices created
2010-05-19 Add proper pattern handling to LaTeXForm created
2010-05-18 Accents mess up @canonicalise created
2010-05-16 Pasting from PDF can introduce spurious ctrl-M created
2010-04-06 Powers do not parse correctly created
2010-04-06 Eliminate metric acts on non-tensors. edited description
2010-04-04 Automatic index raising/lowering not handled in @canonicalise fixed closed with disposition fixed
2010-04-04 Fix dependence on numbers edited description
2010-03-19 @sym/@asym duplicate symbols in tree symmetrisation fixed closed with disposition fixed
2010-02-27 @sym/@asym duplicate symbols in tree symmetrisation fixed created
cadabra-1.39/html/issue-1040b3b57b849b9b2cc8fee189ecb0df52544a75.html000066400000000000000000000052661234107666300235460ustar00rootroot00000000000000 Varying does not handle single-factor terms.

Varying does not handle single-factor terms.

A @vary!(%)( A->a ) on \partial{A} fails. Note that it does work on just 'A'.

Details

Id: 1040b3b57b849b9b2cc8fee189ecb0df52544a75
Type: bugfix
Creation time: 2009-11-14 14:23 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: 1.17 (released 2010-01-28)
Component: cadabra
Status: closed: fixed fixed

Issue log

2010-01-23 21:45 GMT Kasper Peeters <kasper.peeters@...> closed with disposition fixed
Should now work for derivatives and accents, as well as nested products. Documentation and test cases updated as well.
2009-11-14 14:23 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-16b3dc7c2f7508a10da63f93e3407730a757908e.html000066400000000000000000000050531234107666300232370ustar00rootroot00000000000000 Expanding fractional powers fails.

Expanding fractional powers fails.

An @expand_power on A**(3/2) produces A*A*A, obviously incorrect.

Details

Id: 16b3dc7c2f7508a10da63f93e3407730a757908e
Type: bugfix
Creation time: 2009-11-14 14:21 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: 1.17 (released 2010-01-28)
Component: cadabra
Status: closed: fixed fixed

Issue log

2009-12-06 16:10 GMT Kasper Peeters <kasper.peeters@...> closed with disposition fixed
Fixed in 1.17.
2009-11-14 14:21 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-1c7bc5e7512020226c1ca90fb249cab7886b6833.html000066400000000000000000000047511234107666300233070ustar00rootroot00000000000000 Implicit indices need to come in normal and conjugate forms.

Implicit indices need to come in normal and conjugate forms.

Right now, two objects with the same implicit index sitting next to each other are assumed to be connected. However, for e.g. \psi \bar{\chi} with \bar a DiracBar, this is not the case, and the lines go in a different way. In order to determine this, we need to have the concept of indices and conjugate indices.

The can_swap routine currently has an exception for DiracBar objects, but this needs to be generalised.

Details

Id: 1c7bc5e7512020226c1ca90fb249cab7886b6833
Type: bugfix
Creation time: 2009-08-23 09:58 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2009-08-23 09:58 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-2482679b6ec55d83b3f1c431bd7c31047dde8221.html000066400000000000000000000051231234107666300233120ustar00rootroot00000000000000 @collect_factors does not take commutativity properties into account

@collect_factors does not take commutativity properties into account

The following does not do what is expected:

{A,B,C,D,E}::NonCommuting. A B D E B A; @prodsort!(%); @collect_factors!(%);

Details

Id: 2482679b6ec55d83b3f1c431bd7c31047dde8221
Type: bugfix
Creation time: 2010-01-31 19:29 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: 1.18 (released 2010-02-06)
Component: cadabra
Status: closed: fixed fixed

Issue log

2010-02-05 23:18 GMT Kasper Peeters <kasper.peeters@...> closed with disposition fixed
2010-01-31 19:29 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-26a1e390e3639bfcd4eff412054f29beb796a5d3.html000066400000000000000000000047651234107666300235540ustar00rootroot00000000000000 @sym/@asym duplicate symbols in tree symmetrisation

@sym/@asym duplicate symbols in tree symmetrisation

The example

A_{a b} B_{c}; @sym!(%){A_{a b}, B_{c}};

leads to a spurious 'B' appearing in the second term.

Details

Id: 26a1e390e3639bfcd4eff412054f29beb796a5d3
Type: bugfix
Creation time: 2010-02-27 09:26 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: closed: fixed fixed

Issue log

2010-03-19 18:12 GMT Kasper Peeters <kasper.peeters@...> closed with disposition fixed
2010-02-27 09:26 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-2c1e76aeb0f5cf8011ea0bb399c5411e35a1b1e7.html000066400000000000000000000046551234107666300235750ustar00rootroot00000000000000 Single-object factors with brackets do not print correctly

Single-object factors with brackets do not print correctly

An expression of the type

\prod(A){B}

does not print correctly (because this is not valid code), yet it gets generated by input of the form

(A)*B;

Either automatically strip brackets from single factors or do something new with printing; in any case, such expressions will trigger the expression checker and should not be left in the tree.

Details

Id: 2c1e76aeb0f5cf8011ea0bb399c5411e35a1b1e7
Type: bugfix
Creation time: 2009-07-24 13:06 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2009-07-24 13:06 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-346b37f904ab241f53474b9142eb559498066598.html000066400000000000000000000044001234107666300227560ustar00rootroot00000000000000 @canonicalise does not lower/raise indices

@canonicalise does not lower/raise indices

Expressions like

p1_\mu p2^\mu - p1^\mu p2_\mu

do not get canonicalised because @canonicalise does not yet automatically raise and lower indices. This is present in xperm, just needs to be activated properly.

Details

Id: 346b37f904ab241f53474b9142eb559498066598
Type: bugfix
Creation time: 2010-01-28 12:24 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2010-01-28 12:24 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-37d2a9206418dbc66533d3b658d17e4ffb5d8ed2.html000066400000000000000000000043401234107666300234650ustar00rootroot00000000000000 TableauSymmetry assigned to a list fails.

TableauSymmetry assigned to a list fails.

Assigning a TableauSymmetry to a list of items should apply it to each item in turn, but instead it assigns to the list, failing at the parse stage because the \comma node does not have children.

Details

Id: 37d2a9206418dbc66533d3b658d17e4ffb5d8ed2
Type: bugfix
Creation time: 2010-02-08 21:15 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2010-02-08 21:15 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-38a7e972acdc3b14543563da04b16b3968730129.html000066400000000000000000000042651234107666300231560ustar00rootroot00000000000000 @factor_out does not take into account commutativity properties

@factor_out does not take into account commutativity properties

The @factor_out algorithm moves objects through each other without respecting AntiCommuting or NonCommuting.

Details

Id: 38a7e972acdc3b14543563da04b16b3968730129
Type: bugfix
Creation time: 2009-08-20 07:57 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2009-08-20 07:57 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-4db2db8287019b302eafd70dda2d8cdb818f669b.html000066400000000000000000000043731234107666300237020ustar00rootroot00000000000000 Eliminating metrics with position-free indices fails.

Eliminating metrics with position-free indices fails.

This fails:

{m, n, p, q, r}::Indices(vector). g_{m n}::Metric. g^{m n}::InverseMetric. obj10:= 3 g_{m p} g^{m p}; @eliminate_metric!(%);

but it works with position=fixed for the indices.

Details

Id: 4db2db8287019b302eafd70dda2d8cdb818f669b
Type: bugfix
Creation time: 2010-02-02 13:13 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2010-02-02 13:13 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-54b0e71bcc140a8f760bc9835bb6cea84677e76f.html000066400000000000000000000041561234107666300235520ustar00rootroot00000000000000 Accents mess up @canonicalise

Accents mess up @canonicalise

\bar{\psi}_g in an expression messes up the canonicaliser, see email on cadabra-discuss d.d. 17-May-2010.

Details

Id: 54b0e71bcc140a8f760bc9835bb6cea84677e76f
Type: bugfix
Creation time: 2010-05-18 21:58 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2010-05-18 21:58 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-5c264626947a0e6a9f8b454746ecf7a017f429d0.html000066400000000000000000000052451234107666300232610ustar00rootroot00000000000000 Automatic index raising/lowering not handled in @canonicalise

Automatic index raising/lowering not handled in @canonicalise

The @canonicalise algorithm does not yet use the xperm routines which deal with automatic switching of contracted index pairs from upper/lower to lower/upper, e.g. v_a w^a = v^a w_a.

Details

Id: 5c264626947a0e6a9f8b454746ecf7a017f429d0
Type: bugfix
Creation time: 2009-06-03 21:14 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: closed: fixed fixed

Issue log

2010-04-04 19:45 GMT Kasper Peeters <kasper.peeters@...> closed with disposition fixed
Fixed since 1.21.
2009-06-03 21:14 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-6d586ba4d2e7946ba48f17966355b36375e63b8f.html000066400000000000000000000052401234107666300232730ustar00rootroot00000000000000 Accented tensors fail to print

Accented tensors fail to print

While \bar{g} is displayed correctly, \bar{g}_{m n} leads to {\bar}{g}\,_{m n} which obviously cannot print. Curly bracket arguments should not lead to separate bracketing of the head node.

Details

Id: 6d586ba4d2e7946ba48f17966355b36375e63b8f
Type: bugfix
Creation time: 2009-11-14 14:13 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: 1.17 (released 2010-01-28)
Component: cadabra
Status: closed: fixed fixed

Issue log

2009-12-06 11:46 GMT Kasper Peeters <kasper.peeters@...> closed with disposition fixed
Fixed in 1.17.
2009-11-14 14:13 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-871645e20be95eb7b7441170c49d375d770570a0.html000066400000000000000000000042351234107666300231030ustar00rootroot00000000000000 Powers do not parse correctly

Powers do not parse correctly

The input x**{a} parses as

1: {\pow} 2: {x} 3: {} 4: {a}

which is manifestly wrong. Contrast with x**a which works fine.

Details

Id: 871645e20be95eb7b7441170c49d375d770570a0
Type: bugfix
Creation time: 2010-04-06 18:55 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2010-04-06 18:55 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-88b4ab8f3d8dc4314f47c31b2f9c11a050884367.html000066400000000000000000000050511234107666300233160ustar00rootroot00000000000000 Printing problem with \commutator

Printing problem with \commutator

\commutator{X}{Y} is stored correctly, but prints [X,YY] instead.

Details

Id: 88b4ab8f3d8dc4314f47c31b2f9c11a050884367
Type: bugfix
Creation time: 2009-11-16 08:16 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: 1.17 (released 2010-01-28)
Component: cadabra
Status: closed: fixed fixed

Issue log

2009-12-02 21:23 GMT Kasper Peeters <kasper.peeters@...> closed with disposition fixed
Fixed in 1.17.
2009-11-16 08:16 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-9258c825583707f6bf901795c9d4e2a82f13e0d3.html000066400000000000000000000054631234107666300232110ustar00rootroot00000000000000 Depends property overwrites earlier ones.

Depends property overwrites earlier ones.

The following fails: \hat{#}::Accent. \partial{#}::PartialDerivative. A::Depends(\hat). A::Depends(\partial). \hat{A}; @unwrap!(%);

Putting all dependencies in one works though. Formalise or fix.

Details

Id: 9258c825583707f6bf901795c9d4e2a82f13e0d3
Type: bugfix
Creation time: 2009-11-14 14:24 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: 1.17 (released 2010-01-28)
Component: cadabra
Status: closed: won't fix won't fix

Issue log

2010-01-23 21:50 GMT Kasper Peeters <kasper.peeters@...> closed with disposition wontfix
Has been documented now in the Depends documentation. Won't fix for the time being as there is a simple workaround.
2009-11-14 14:24 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-96cc2f197c8a31e580777b96155261bdb581005c.html000066400000000000000000000046551234107666300231740ustar00rootroot00000000000000 'Derivation' property

'Derivation' property

A 'Derivation' should be an object which non-commutes with everything that 'Depends' on it, and for which @prodrule gives

D a b c -> (D a) b c + a (D b) c + a b (D c)

Moreover, '@prodflatten' should never take the brackets away in these situations.

It would be good to have a solution in mind which can easily be extended to work with graded algebras, so that exterior derivatives can be handled with the same logic.

Details

Id: 96cc2f197c8a31e580777b96155261bdb581005c
Type: feature
Creation time: 2009-08-18 17:40 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2009-08-18 17:40 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-9c8f132023a13bdea10ef87e26d37d681705a8d1.html000066400000000000000000000053731234107666300233730ustar00rootroot00000000000000 Derivatives of sums do not always display correctly in notebook

Derivatives of sums do not always display correctly in notebook

While expressions of the type \nabla_{f}{a_{c} d+b_{c}} print correctly, the ones without explicit derivative index, \nabla{a_{c} d+b_{c}}, fail to print brackets.

Details

Id: 9c8f132023a13bdea10ef87e26d37d681705a8d1
Type: bugfix
Creation time: 2009-09-02 19:08 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: 1.17 (released 2010-01-28)
Component: cadabra
Status: closed: fixed fixed

Issue log

2010-01-20 21:26 GMT Kasper Peeters <kasper.peeters@...> closed with disposition fixed
Hopefully finally fixed now, brackets remain somewhat of a hack...
2009-09-02 19:09 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-a2bec73e247cc89c7cfca20ee457e5295de9475e.html000066400000000000000000000062651234107666300237270ustar00rootroot00000000000000 Deleting last cell of notebook sometimes produces warnings

Deleting last cell of notebook sometimes produces warnings

Start cadabra, add another cell, then immediately alt-delete it: a gtk warning is produced and the cursor disappears.

Details

Id: a2bec73e247cc89c7cfca20ee457e5295de9475e
Type: bugfix
Creation time: 2009-11-16 08:16 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: 1.18 (released 2010-02-06)
Component: cadabra
Status: closed: fixed fixed

Issue log

2010-02-05 23:17 GMT Kasper Peeters <kasper.peeters@...> closed with disposition fixed
Also most likely fixes various other redo/undo bugs. Also goes along with removing calls to gtk_update_pending which seems to be problematic in many respects. Might fix the OS X segfaults.
2010-01-28 13:42 GMT Kasper Peeters <kasper.peeters@...> assigned to release 1.18 from 1.17
Not quite debugged yet, a few issues remaining.
2009-11-16 08:16 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-a581c29d3f2a279c34df52be8f4b8761dabc18fa.html000066400000000000000000000043051234107666300237010ustar00rootroot00000000000000 Add proper pattern handling to LaTeXForm

Add proper pattern handling to LaTeXForm

Currently it is not possible to use LaTeXForm for output like M_{a b c} -> {\stackrel{a}{M}}_{b c} because the pattern objects cannot be used in the LaTeXForm string.

Details

Id: a581c29d3f2a279c34df52be8f4b8761dabc18fa
Type: feature
Creation time: 2010-05-19 17:03 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2010-05-19 17:03 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-a7f3c6de890010983ccd353a949975bd1b4f66b3.html000066400000000000000000000042011234107666300234050ustar00rootroot00000000000000 @factor_out does not handle powers

@factor_out does not handle powers

A @factor_out on 'q' does not factor out 'q**2'. Workaround: add 'q**2' to the list of symbols to be factored out.

Details

Id: a7f3c6de890010983ccd353a949975bd1b4f66b3
Type: bugfix
Creation time: 2009-08-20 07:58 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2009-08-20 07:58 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-ada88ddc28be6f0f3567fc2d0f50fb3dc64a37b4.html000066400000000000000000000042731234107666300240400ustar00rootroot00000000000000 @fierz does not produce useful error messages.

@fierz does not produce useful error messages.

When calling @fierz on an expression which cannot be Fierz transformed, there are typically no useful error messages about why the algorithm failed.

Details

Id: ada88ddc28be6f0f3567fc2d0f50fb3dc64a37b4
Type: bugfix
Creation time: 2009-08-23 09:20 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2009-08-23 09:20 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-b5dc914a9876677a3e1059466fd741fb4d2ab336.html000066400000000000000000000052211234107666300233300ustar00rootroot00000000000000 Worldsheet susy sample is broken

Worldsheet susy sample is broken

LaTeXForm is not handled properly in the worldsheet susy sample notebook. Fixing that messes up the rest of the output...

Details

Id: b5dc914a9876677a3e1059466fd741fb4d2ab336
Type: bugfix
Creation time: 2010-02-05 21:08 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: closed: fixed fixed

Issue log

2010-02-07 21:16 GMT Kasper Peeters <kasper.peeters@...> closed with disposition fixed
Was related to @vary which should now no longer be applied recursively; dropping the exclamation mark did the trick.
2010-02-05 21:08 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-b5f5ed9ac93dd64deddecc606872e6a00009d6be.html000066400000000000000000000042001234107666300240330ustar00rootroot00000000000000 Kernel hang

Kernel hang

A kernel hang has been reported by Kevin Horton, involving loading a notebook while another one is still in memory. Reproducible on Linux, reported 7-Feb-2010.

Details

Id: b5f5ed9ac93dd64deddecc606872e6a00009d6be
Type: bugfix
Creation time: 2010-02-07 21:49 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2010-02-07 21:49 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-c6f19ea6617d8186461181296226988ae7111708.html000066400000000000000000000045271234107666300227100ustar00rootroot00000000000000 Numerical indices default to position=free.

Numerical indices default to position=free.

Numerical indices default to position=free and hence n^0 equals n_0. Could probably benefit from a declaration of index properties directly at the level of the tensor, rather than the indices themselves (though this would then require declaration for every tensor, instead of only the index set as currently).

Details

Id: c6f19ea6617d8186461181296226988ae7111708
Type: bugfix
Creation time: 2009-11-18 00:55 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2009-11-18 00:55 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-ca0ea385450a3a152cc01829d27cb86d945aca1d.html000066400000000000000000000042461234107666300235120ustar00rootroot00000000000000 Pasting from PDF can introduce spurious ctrl-M

Pasting from PDF can introduce spurious ctrl-M

When pasting from PDF on a Mac (and possibly elsewhere), there are spurious ctrl-M characters which mess up the parser. Remove.

Details

Id: ca0ea385450a3a152cc01829d27cb86d945aca1d
Type: bugfix
Creation time: 2010-05-16 19:31 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2010-05-16 19:31 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-d3968c05090854806ec986d696e99a887d458b18.html000066400000000000000000000050651234107666300231050ustar00rootroot00000000000000 Fix dependence on numbers

Fix dependence on numbers

A declaration of the type a::Depends(0) will introduce dependence on all rationals (as the overall constant is always ignored).

Edit: can be circumvented by using a notation with \partial which mentions the coordinate name, i.e.

\partial_{x^{0}}{a} + \partial_{x^{1}}{a};

(see test 37 in tests/fieldtheory.cdb)

Details

Id: d3968c05090854806ec986d696e99a887d458b18
Type: bugfix
Creation time: 2009-11-18 00:52 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2010-04-04 19:44 GMT Kasper Peeters <kasper.peeters@...> edited description
2009-11-18 00:52 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-d96ff69906114cf2e375be83d1679277743d6bec.html000066400000000000000000000042301234107666300233520ustar00rootroot00000000000000 Repeated divisions are buggy

Repeated divisions are buggy

Constructions of the type 1/a/b are broken,

1/2/3;1/2/(3+4);1/2/(x+y);1/x/(x+y);1/x/(3+4);

will only parse correctly for the first three.

Details

Id: d96ff69906114cf2e375be83d1679277743d6bec
Type: bugfix
Creation time: 2010-02-08 15:47 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2010-02-08 15:47 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-db53ba8697972d02ee83a31fb26a798f4ef0a7d0.html000066400000000000000000000056761234107666300235630ustar00rootroot00000000000000 Eliminate metric acts on non-tensors.

Eliminate metric acts on non-tensors.

Calling eliminate_metric on expressions which are not actually tensors still raises/lowers the indices, e.g.

{m,n,o}::Indices. \partial{#}::PartialDerivative. g_{m n}::Metric. g^{m n}::InverseMetric.

\partial_{i}{g_{m n}} g^{n o}; @eliminate_metric!(%);

Fix requires associating a metric wrt. a derivative, e.g.

\partial{#}::PartialDerivative(metric=g). \nabla{#}::Derivative(metric=g).

etc.

Edit: can also fix this by adding a Depends, which looks less clumsy and requires no additional notation:

g_{m n}::Depends(\partial).

That way we can even handle special cases in which the metric does not depend on coordinates even though in general it would.

Details

Id: db53ba8697972d02ee83a31fb26a798f4ef0a7d0
Type: bugfix
Creation time: 2010-02-06 15:33 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2010-04-06 14:10 GMT Kasper Peeters <kasper.peeters@...> edited description
2010-02-06 15:33 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-e21ce60551528df4aaf0b0226544cd0a2f278e96.html000066400000000000000000000042131234107666300233560ustar00rootroot00000000000000 Superfluous square brackets with [..] action

Superfluous square brackets with [..] action

This produces extra square brackets:

@distribute[a*(b+c)];

Wrong flag gets copied somewhere.

Details

Id: e21ce60551528df4aaf0b0226544cd0a2f278e96
Type: bugfix
Creation time: 2010-02-08 21:17 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2010-02-08 21:17 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-e265d6222f658da087b232a55d9aa05122a523a7.html000066400000000000000000000044431234107666300232160ustar00rootroot00000000000000 Redraw segfault on OS X

Redraw segfault on OS X

When dragging (or resizing?) a window on OS X, the quick successive calls to XCadabra::on_configure_event and the subsequent redraw_cells result in a segfault somewhere inside convert_subset of the TeX engine. Might be because GTK on the mac calls the redraw handler in a different way than on X11.

Details

Id: e265d6222f658da087b232a55d9aa05122a523a7
Type: bugfix
Creation time: 2009-08-21 09:51 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2009-08-21 09:51 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/issue-f2ada64adc88a3b4014456bc2d50863f242a1f12.html000066400000000000000000000070101234107666300234200ustar00rootroot00000000000000 Conversion of / to \frac misplaces bracket types.

Conversion of / to \frac misplaces bracket types.

An expression of the form

( 1/\sqrt{2 B b**2} )**2

gets translated to

{ \frac(1)(\sqrt{2 B b**2}) }**2

whereas it should have been

( \frac{1}{\sqrt{2 B b**2}} )**2

I.e. the brackets around the '/' should sit on the \frac, not on each of the children of \frac.

The actual problem sits in preprocessor.cc, which does

[a*b] -> \prod[a][b] [a/b] -> \frac[a][b] [a/b]**2 -> \pow{\frac[a][b]}{2}

but

[\frac{a}{b}] -> \frac{a}{b} [\frac{a}{b}]**2 -> \pow[\frac{a}{b}]

So the 'bug' is working the other way around: if you enter things in [\frac{a}{b}] notation, you should expect it to be different from [a/b]. Not sure whether this should be 'fixed'; postponing for the time being.

Details

Id: f2ada64adc88a3b4014456bc2d50863f242a1f12
Type: bugfix
Creation time: 2010-01-30 20:41 GMT
Creator: Kasper Peeters <kasper.peeters@...>
Release: unassigned
Component: cadabra
Status: unstarted

Issue log

2010-02-06 18:12 GMT Kasper Peeters <kasper.peeters@...> edited description
2010-02-06 18:10 GMT Kasper Peeters <kasper.peeters@...> unassigned from release 1.18
2010-02-05 00:26 GMT Kasper Peeters <kasper.peeters@...> edited description
2010-01-30 20:41 GMT Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/release-1.15.html000066400000000000000000000045571234107666300167020ustar00rootroot00000000000000 cadabra release 1.15

cadabra release 1.15

Status: released
Release time: 2009-08-18 17:37 GMT
Completion:                                                    100%
0 / 0 issues

Issues

No issues assigned to this release.

Recent activity for this release

Release log

Tue Aug 18 17:37:56 UTC 2009 Kasper Peeters <kasper.peeters@...> released
Tue Aug 18 17:37:15 UTC 2009 Kasper Peeters <kasper.peeters@...> created
Stable version release before Ubuntu Karmic 9.10 freeze.
cadabra-1.39/html/release-1.17.html000066400000000000000000000175571234107666300167100ustar00rootroot00000000000000 cadabra release 1.17

cadabra release 1.17

Status: released
Release time: 2010-01-28 13:43 GMT
Completion:                                                    100%
6 / 6 issues

Issues

fixed 2009-11-16 Printing problem with \commutator
won't fix 2009-11-14 Depends property overwrites earlier ones.
fixed 2009-11-14 Varying does not handle single-factor terms.
fixed 2009-11-14 Expanding fractional powers fails.
fixed 2009-11-14 Accented tensors fail to print
fixed 2009-09-02 Derivatives of sums do not always display correctly in notebook

Recent activity for this release

2010-01-23 Depends property overwrites earlier ones. won't fix closed with disposition wontfix
2010-01-23 Varying does not handle single-factor terms. fixed closed with disposition fixed
2010-01-20 Derivatives of sums do not always display correctly in notebook fixed closed with disposition fixed
2009-12-06 Expanding fractional powers fails. fixed closed with disposition fixed
2009-12-06 Accented tensors fail to print fixed closed with disposition fixed
2009-12-02 Printing problem with \commutator fixed closed with disposition fixed
2009-11-16 Printing problem with \commutator fixed created
2009-11-14 Depends property overwrites earlier ones. won't fix created
2009-11-14 Varying does not handle single-factor terms. fixed created
2009-11-14 Expanding fractional powers fails. fixed created

Release log

Thu Jan 28 13:43:06 UTC 2010 Kasper Peeters <kasper.peeters@...> released
Released on PPA and as source only.
Wed Sep 02 19:07:21 UTC 2009 Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/release-1.18.html000066400000000000000000000117331234107666300166770ustar00rootroot00000000000000 cadabra release 1.18

cadabra release 1.18

Status: released
Release time: 2010-02-06 18:10 GMT
Completion:                                                    100%
2 / 2 issues

Issues

fixed 2010-01-31 @collect_factors does not take commutativity properties into account
fixed 2009-11-16 Deleting last cell of notebook sometimes produces warnings

Recent activity for this release

2010-02-05 @collect_factors does not take commutativity properties into account fixed closed with disposition fixed
2010-02-05 Deleting last cell of notebook sometimes produces warnings fixed closed with disposition fixed
2010-01-31 @collect_factors does not take commutativity properties into account fixed created
2010-01-28 Deleting last cell of notebook sometimes produces warnings fixed assigned to release 1.18 from 1.17
2009-11-16 Deleting last cell of notebook sometimes produces warnings fixed created

Release log

Sat Feb 06 18:10:31 UTC 2010 Kasper Peeters <kasper.peeters@...> released
Thu Jan 28 13:41:27 UTC 2010 Kasper Peeters <kasper.peeters@...> created
to be uploaded to Debian in time for Ubuntu Lucid freeze
cadabra-1.39/html/release-1.21.html000066400000000000000000000036071234107666300166720ustar00rootroot00000000000000 cadabra release 1.21

cadabra release 1.21

Status: unreleased
Completion:                                                    100%
0 / 0 issues

Issues

No issues assigned to this release.

Recent activity for this release

Release log

Sun Feb 07 21:17:02 UTC 2010 Kasper Peeters <kasper.peeters@...> created
cadabra-1.39/html/unassigned.html000066400000000000000000000404611234107666300170320ustar00rootroot00000000000000 Issues not assigned to any release

Issues not assigned to any release

All issues

2010-06-17 @fierz does not work when there are no gamma matrices
2010-05-19 Add proper pattern handling to LaTeXForm
2010-05-18 Accents mess up @canonicalise
2010-05-16 Pasting from PDF can introduce spurious ctrl-M
2010-04-06 Powers do not parse correctly
fixed 2010-02-27 @sym/@asym duplicate symbols in tree symmetrisation
2010-02-08 Superfluous square brackets with [..] action
2010-02-08 TableauSymmetry assigned to a list fails.
2010-02-08 Repeated divisions are buggy
2010-02-07 Kernel hang
2010-02-06 Eliminate metric acts on non-tensors.
fixed 2010-02-05 Worldsheet susy sample is broken
2010-02-02 Eliminating metrics with position-free indices fails.
2010-01-30 Conversion of / to \frac misplaces bracket types.
2009-11-18 Numerical indices default to position=free.
2009-11-18 Fix dependence on numbers
2009-08-23 Implicit indices need to come in normal and conjugate forms.
2009-08-23 @fierz does not produce useful error messages.
2009-08-21 Redraw segfault on OS X
2009-08-20 @factor_out does not handle powers
2009-08-20 @factor_out does not take into account commutativity properties
2009-08-18 'Derivation' property
2009-07-24 Single-object factors with brackets do not print correctly
2009-06-30 Cleanup output routines
2009-06-29 Make @canonicalise work on functional arguments
fixed 2009-06-29 Re-LaTeX TeX cells on close
2009-06-27 Fix output messages to be TeX
2009-06-27 Bracket flexibility leads to inconsistencies
2009-06-26 Handle PartialDerivatives with no arguments
fixed 2009-06-26 Dividing active cell does not work anymore
2009-06-19 Potential bug with A_{m m} -> replacements
fixed 2009-06-03 Automatic index raising/lowering not handled in @canonicalise
2009-05-26 Unify handling of commutation signs
in progress 2009-05-26 Inherit<...> is not flexible enough
fixed 2009-01-19 Crash with tensors in numerators
2009-01-03 @canonicalise does not honor ImplicitIndex
2008-12-11 Introduce a notation for 'a range of objects'
fixed 2008-11-24 Nested \partial's do not always flatten automatically.
fixed 2008-11-17 Single-factor replacements with dummy names fail.
fixed 2008-11-14 @eliminate_kr does not work on sums
fixed 2008-11-14 XCadabra breaks when a .cadabra is present
2008-08-29 Add support for differential 'd'
fixed 2008-08-25 Ask user before overwriting existing files.
2008-08-24 Cursor position after crash
2008-08-24 @factor_out problems with tensors
fixed 2008-08-24 Multiple-level undo in GUI
cadabra-1.39/install-sh000077500000000000000000000144061234107666300150440ustar00rootroot00000000000000#!/bin/sh # # install - install a program, script, or datafile # # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: chmodcmd="" else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 cadabra-1.39/man/000077500000000000000000000000001234107666300136065ustar00rootroot00000000000000cadabra-1.39/man/man1/000077500000000000000000000000001234107666300144425ustar00rootroot00000000000000cadabra-1.39/man/man1/cadabra.1000066400000000000000000000047371234107666300161140ustar00rootroot00000000000000.TH CADABRA 1 "Dec 14, 2006" "" "" .\" .\" Man page written by Kasper Peeters .\" .\" 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., 675 Mass Ave, Cambridge, MA 02139, USA. .\" .\" .SH NAME cadabra \- field\-theory motivated computer algebra system .SH SYNOPSIS .BR "cadabra" .SH DESCRIPTION .B Cadabra is a computer algebra system for the manipulation of tensorial expressions. The output of cadabra is either plain text or UTF8 encoded Unicode (see the environment variables described below). The line\-breaking properties of the latter are used to wrap large expressions are reasonable points. In addition to the standard output, cadabra can print status information, which is wrapped in special ... blocks. .SH OPTIONS .TP \fB \-\-silent\fR Disables all output, except for output generated by the @print algorithm. .TP \fB \-\-loginput\fR Copy the input into the log file. .TP \fB \-\-input filename\fR Read the indicated file as input before switching to console input. .TP \fB \-\-prompt string\fR Set the prompt of the interactive session to the indicated string. .SH ENVIRONMENT VARIABLES The following variables toggle various features on or off, depending on whether the variable is set or not: .TP \fB CDB_PRINTSTAR\fR Display a star to indicate products. Without this setting, a space is used. .TP \fB CDB_USE_UTF8\fR Use UTF8 encoding for output. This in particular will introduce non\-breakable spaces to group objects together, as well as zero-width non\-breakable spaces to prevent line\-breaks after brackets, underscore and caret symbols. When this variable is not set, the output will be plain ASCII without any special symbols. .SH SEE ALSO .BR xcadabra (1). See the web page at .BR "http://www.aei.mpg.de/~peekas/cadabra/" for binaries, example calculations and the full manual. .SH AUTHORS Kasper Peeters cadabra-1.39/man/man1/xcadabra.1000066400000000000000000000022751234107666300162770ustar00rootroot00000000000000.TH XCADABRA 1 "Dec 14, 2006" "" "" .\" .\" Man page written by Kasper Peeters .\" .\" 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., 675 Mass Ave, Cambridge, MA 02139, USA. .\" .\" .SH NAME xcadabra \- gtk front\-end for cadabra .SH SYNOPSIS .BR "xcadabra" .SH DESCRIPTION .B Xcadabra is a graphical front\-end for the computer algebra system .B cadabra. .SH SEE ALSO .BR cadabra (1). See the web page at .BR "http://www.aei.mpg.de/~peekas/cadabra/" for more information and up\-to\-date sample notebooks. .SH AUTHORS Kasper Peeters cadabra-1.39/osx/000077500000000000000000000000001234107666300136445ustar00rootroot00000000000000cadabra-1.39/osx/.gitignore000066400000000000000000000000401234107666300156260ustar00rootroot00000000000000.DS_Store libs cadabra xcadabra cadabra-1.39/osx/Cadabra.app/000077500000000000000000000000001234107666300157405ustar00rootroot00000000000000cadabra-1.39/osx/Cadabra.app/Contents/000077500000000000000000000000001234107666300175355ustar00rootroot00000000000000cadabra-1.39/osx/Cadabra.app/Contents/Info.plist000066400000000000000000000013371234107666300215110ustar00rootroot00000000000000 CFBundleGetInfoString Cadabra CFBundleExecutable launch CFBundleIdentifier com.phi-sci.cadabra CFBundleName cadabra CFBundleIconFile cadabra.icns CFBundleShortVersionString 1.50 CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType APPL IFMajorVersion 1 cadabra-1.39/osx/Cadabra.app/Contents/MacOS/000077500000000000000000000000001234107666300204775ustar00rootroot00000000000000cadabra-1.39/osx/Cadabra.app/Contents/MacOS/launch000077500000000000000000000000771234107666300217030ustar00rootroot00000000000000#!/bin/bash cd "${0%/*}" #./cadabra open -a Terminal ./cadabra cadabra-1.39/osx/Cadabra.app/Contents/Resources/000077500000000000000000000000001234107666300215075ustar00rootroot00000000000000cadabra-1.39/osx/Cadabra.app/Contents/Resources/cadabra.icns000066400000000000000000010461621234107666300237540ustar00rootroot00000000000000icnsLris32!+ (%! *6 51-)&! *6 3/,($*6 1/*&$*6 40-)&  *6-&*$# *60"%! *40/,! *#1/*$*/0,($  *2/+&*(-)  *1    +1.*+&"  (0,($  "  ^~ |vtnid^XP(| B| >| 9| 4|~1|IpW6+|.D#|Ihz|EK5! |o0Cj(|Cvx?#W9,|Wce}\HK@0|+r:0G"z3Qkgb]VOKC<2 ) '$  )6 51-)&!)6 3/,($)6 1/*&$)6 40-)& )6-&*$# )60"%! )40/,! )#1/*$)/0,($  )2/+&)(-)  )1    )1.*&"   '0,($   s8mkƹyƴ}kYhоvdRcɷo]K^°ygUCY;r`N;:631.,( T!TTTTTTTTTToZfoT5*dxf1nE>Tfj'd TZ~] TwSy= T}: TkOYT74(q7@TNe;v/6Tce=&A'T"Un/~ TR=1+Ud7:?UTL9N}T;S9L/Td96Fv'4''wfT84i5 T":$C-S~wBPRtQ Z>!GEDB?>;8542.,)($"  6531/-,*(&$# 642//-+)&%#"65310.,*(&#"6531/-+)'%$! 6420.,*('$# 6531.-+)(&$#  642//-+)&%#" 65310.,*(&#" 6431/-,*(%#!  6420.,*('$#  650"()($#  6/ $#  6""10.,* " 6)31/-,*!!  66(420/,*($!  65431.-+)(#   6$420.-+)'&!  68+310.,*(&$"  6 331/-,*(%#!   6410/,*(&#! 6 31.-+)(%    6/0.-+)'#  61/-,*("    64*&,& "  641/%$!   531/-+)'%$!     420.-+)'&#  31/-,*(&$"  2//-+)&%#" 10/,*(&%$!    l8mk¾Ǿ~ulcZQú{ri`WNȿwne\SJż|sjaXOFypg^ULCƽ~ulcZQH?úzqh_VMD;ȿwne\SJA8Ļ|sjaXOF=4xof]TKB90~ƽë~ulcZQH?6-}קzqh_VMD;2)z¤wnd[RI@7.%y|sjaXOF=4+"x쥜xof]TKB90'vƽ֢~ulcZPG>5,#s¹zqh_VMD;2) rǾ̺q[RI@7Xpx$qĻxlXOF<]!4oof]TKBR';mƽDz}ܯbYPGA,#l¹Ҟ~VMDk]IмlǾاڜmͺRI@1%=lۭriNE<*!slîʵofKB>'Alżkc_G>e#ll¹}ğLC:Zf}lǾvmk`RI@7%#lú{ri`WNE<9!lwne\SJA8AF lÿ~zwwwwih32     654310/-,,*((&$#" 65321/.-,**('%$#! 6 54310/.-+*)'&&$" 6 54210/-,+)(&&##!6 431/./-+*)(&%$$" 6!54310/-,,*((&$#" 64321/.-,**('%$#! 6"54310/.-+*)'&&$"  6"53210.-,+)('%##! 6"431/./-+*)(&%$$"  6#54310/-,,*(&&%##! 64321/.-,**('%$#! 6$54310/.-+*)'&&$"  6$53210.-,+)('%##! 6$431/./-+*)(&%$$"   6%54210/-,+)(&&%##! 641"(**( $#! 6&. ("#"  6(5 '10.-,+ #! 6)2 21/./-+*'$$"   6*24210/-,+)( ##!  65 4321/.-,**(#!  6+14310/-,,*(("  6,.53210.-,+)('#!  61431/..-+*)'& "    66154210/-,+)(&&%##!  66 #4321/.-,**('%$#"  7 66-4310/-,,*((&$#"   ,66 53210.-,+)('%##!   ,66 4310/.-+*)'&&     +66 4210/-,+)(&&%!   +66 32/./-+*)(&%"     (66#110/-,,*((&$    665 10.-,+)('%!   *665&,/.-+*)'& "    )6654&-,+)(##!   )66431%  $$"    (654310/)&&$#"   65321/.-,**('%$#!  #54310/.-+*)'&&$"    &54210/-,+)('%##!  '431/./-+*)(&%$$"   &4310/-,,*((&$#"   321/.-,**('%$#!  %310/.-+*)'&&$"  %210.-,+)('%##!     210.-,,)(''&%$#"... . . . . ." ." ." . . .$ .$.$..%jQ?9N~^.&:OdkQO\.(Lz0D.)'F . O?3. '4dW.H $u.,Tq.94R.3,.ah%T'*82,~xrlf`ZTNHB<60*ľɬ|vpjd^XRLF@:4.(ǩysmga[UOIC=71+%}wqke_YSMGA;5/)#񫥟ztnhb\VPJD>82,& ܨ~xrlf`ZTNHB<60*$ľǦ|vpjd^WQKE?93-'!ysmga[UOIC=71+%ſ򧡛}wqke_YSMGA;5/)"¼Ȥztnhb\VPJD>82,& ~xrlf`ZTNHB<60*$ľž}c]WQKE?934fvFa[UOIC=9iP ſŸwqst^XRLF@=j("'G¼vnhb\VPJD>x,& 1l嫜lf`ZTNHBV/)#m6ý㟙{c]WQKE?Y-'!٨㱝|[UOIC=1+Ѵſ̠qXRLF@I.(m|¼פtniVPJD>v,& ШqkeUMGA;J)#㺫uoicQKE?9-'!4ѽsmgaOIC8 }wְɳXMGA;5)x{ý{uoiteWQKE?9?'!.' ~xrlf`ZTNHB<6n}$ ľ|vpjd^XRLF@:4F" ¼ztnhb\VPIC=71% ſ}wqke_YSMGA;5/)# it32J   654332100././-,+,+*)*)(0'&&%&%$##$#!  6-5544332211/00//..--,,++**))(('&'&%%$#$##"!"  65544332100//./-,,++**))(1'&&%&%$##$"! ! 6554432100./..--,,+,**)*('&&%$#$##"#!  6 5544332211/0/- ,,++**))(('&%,$$#$"!"! 654332100././-,+,+*)*)(2'&&%&#$##"#!  6K5544332211/00//..--,,++**))(('&'&%%$#$##"!"  65544332100//./-,+*)(3'&&%&%$##$"! ! 6554432100./..--,,+,**)*('&&%$#$##"#"  655443321/0/- ,,++**))(('&%.$$#$"!"! 654332100././-,+,+*)*)(4'&&%&#$##"#!  6"5544332211/00//..--,,++**))(('&'&%%$%##"!"  65544332100//./-,+*)(2'&&%&%$##$"! ! 6554432100./..--,,++**))(&'&&%$#$##"#"    655443321/0/- ,,++**))(('&%4$$#$"! !  654332100./..-,+,+*)*)(:'&&%&#$##"#!   6"5544332211/00//..--,,++**))(('&'&%%$%##"!"    654332100//./-,+*)(2'&&%&%$##$#! !  655443211/00./..--,,++**))(&'&&%$#$##"#"    655443321/0/-=,,++**))((''&&%&%$$#$"! !  6554432100./..-,+,+*)*)(<'&&%&#$##"#!   65544332211/00//.-,,++**))(('&'&%%$%##"!"    654332100//./-,+*)(='&&%&%$##$#! !  65544332211/00./..--,,++**))(&'&&%$#$##"#"   655443321/0/-=,,++**))((''&&%&%$$#$"! !   6554432100./..-,+,+*)*)(>'&&%$#$##"#!    6 5544332211/0/.-,,++**))(('&'&%%$%##"!"   654332100//./-,+,+*)*)(?'&&%&%$##$#! !   65544332211/00./..--,,++**))(&'&%%$#$##"!"   65544332100//./-=,,++**))((''&&%&%$$#$"! !   6554432100./..-,+,**)*(*'&&%$#$##"#!    6 5544332211/0/.-,,++**))(('&'&%%$%#$"!"!  654332100././-,+,+*)*)(A'&&%&%$##$#! !   6-5544332211/00./..--,,++**))(('&'&%%$#$##"!"     65544332100//./-=,,++**))((''&&%&%$$#$"! !   6554432100./..--,,+,**)*(*'&&%$#$##"#!    6 5544332211/0/.- ,,++**))(('&%=$$#$"!"!  654332100././-,+,+*)*)(C'&&%&%$##$#!    6-5544332211/00//..--,,++**))(('&'&%%$#$##"!"     65544332100//./-,,++**))(2'&&%&%$##$"! !  6554432100./..--,,+,**)*('&&%$#$##"#!      6 5544332211/0/- ,,++**))(('&%?$$#$"!"!  654332100././-,+,+*)*)(E'&&%&#$##"#!    6K5544332211/00//..--,,++**))(('&'&%%$#$##"!"   655443320&  +,+*)(2'%&%$##$"! !  655443,  ,**)*(' $#$##"#"     6552   O %*))(('&%$$#$"!"!  62!+././--( *)(C #$##"#!    65%1/00//..--,,+(('$%##"!"   6, +100//./-,+%(. %$##$"! !   65 (32100./..--,,++**$  #$##"#"     612321/0/- ,,++**)1$$#$"! !    6*&4332100./..-,+,+*)*)A#$##"#!     6$-4332211/00//..--,,++**))(&( $$##"!"    6#.44332100//./-,+*)(( A$##$#! !    6#-443211/00./..--,,++**))( $##"#"      6')5443321/0/- ,,++**))(('%-$$#$"! !   6+54432100./..-,+,+*)*)('B $##"#!     63 5544332211/0/.- ,,++**))(('&' '$##"!"    6154332100//./-,+*)('&B##$#! !    6!5544332211/00./..--,,++**))(&'&$##"#"      615443321/0//./-=,,++**))((''&& $#$"! !   6$554432100./..-,+,+*)*)(F'&&##"#!     6' 65544332211/0/.-8,,++**))(('&'&%##"!"    6 !654332100//./-,+,+*)*)(F'&&%##$#! !    6&45544332211/00./..--,,++**))(&'&%% ##"!"     6 65544332100//./-=,,++**))((''&&%&  #$"! !   6,.554432100./..--,,+,**)*(*'&&%$#$##"#!     6 65544332211/0/.- ,,++**))(('&'&%'$$#$"!"!   65654332100././-,+,+*)*)(F'&&%&%$##$#! !    6(.-5544332211/00./..--,,++**))(('&'&%%$#$##"!"     665544332100//./-=,,++**))((''&&%&%$##$"! !   6 554432100./..--,,+,**)*('&&%$#$##"#!    64 !5544332211/0/.- ,,++**))(('&%$$#$"!"!   6+,54332100././-,+,+*)*)(!'&&%&%$##"#!      6".4544332211/00//..--,,++**))(('&'&%%$#$##"!"     6 5544332100//./-,,++*)(2'&&%&%$##$"! !     654432100./..--,,+,**)*('&&%$#$##"#"      6 544332211/0/- ,,++**))(('&%:$$#$"!"!    64332100././-,+,+*)*)(F'&&%&#$"#!     6J!44332211/00//..--,,++**))(('&'&%%$#$"!"     6#44332100//./-,+*)('&&%&%$"! !    6"432100./..--,,+,**)*(&'&&%$#$ #"       6%!43321/0/- ,,++**))(('&%$ !"!  $    6/4332100./..-,+,+*)*)('&&%&#$ #!  #   6:332211/00//..--,,++**))(('&'&%%$$"!"     6 332100//./-,+*)('&&%&%$ "! !     6)232100./..--,,++**))(&'&&%$##"    6$21/0/- ,,++**))(('&%&%""! !    6 2100./..-,+,+*)*)(#'&&%&# "#!     63<-11/00//..--,,++**))(('&'&%%$ !"!"     65%1100//./-,+*)('&&%& $#! !      6554!/00./..--,,++**))(&'&&$ #"#"      65542 '0/-1,,++**))((''&&#$"! !    655443/&./..-,+,+*)*)('&##"#!      6554433- /.-#,,++**))(('& "$##"!"     654332/-, +*)*)(( %$##$#! !     6 5544332211 (++**(" $$#$##"!"      6554433210/"%&%$$#$"! !     6554432100..  '&&%$#$##"#!       6 5544332211/0/.--%"('&'&%%$##"!"!     654332100././-,+,+*)*)('&&%&%$##$#! !       6-5544332211/00./..--,,++**))(('&'&%%$#$##"!"       65544332100//./-%,,++**))((''&&%&%$$#$"! !    66554432100./..--,,+,**)*()'&&%$#$##"#!       665544332211/0/.- ,,++**))(('&%$$#$"!"! '  6654332100././-,+,+*)*)(F'&&%&%$##$#! !    /65544332211/00./..--,,++**))(('&'&%%$#$##"!"    65544332100//./-=,,++**))((''&&%&%$##$"! !     554432100./..--,,+,**)*("'&&%$#$##"#!       5544332211/0/.- ,,++**))(('&%:$$#$"!"!     54332100././-,+,+*)*)(F'&&%&#$##"#!     -544332211/00//..--,,++**))(('&'&%%$#$##"!"    544332100//./-,,++*)(2'&&%&%$##$"! !   4432100./..--,,+,**)*('&&%$#$##"#"       44332211/0/- ,,++**))(('&%:$$#$"!"!   44332100././-,+,+*)*)(F'&&%&#$##"#!     I4332211/00//..--,,++**))(('&'&%%$#$##"!"    4332100//./-,+*)(2'&&%&%$##$"! !   32100./..--,,+,**)*(&'&&%$#$##"#"      3321/0/- ,,++**))(('&%@$$#$"!"!   332100./..-,+,+*)*)(F'&&%&#$##"#!     32211/00//..--,,++**))(('&'&%%$%##"!"    32100//./-,+*)(2'&&%&%$##$"! !     66554544322121100/..-.--,,++*)**)((''&&%%$$##"#!"!!   22 222 22 22 2 22  2 2  2 2 2  2 2  2 2  2   2 2  2 2  2  2 2 2  2 2   2 2  2  2 2  22 222 2  2 2~^A6-&,9Hm:J2X(-s302`"!,.!'CU 2MBnY# oS 2Z 3z_ fd 26 tp,2Q|v P2)Jx{ 2} u@  2l+ 2i/M2j hv2v| 2\& 20 /G 27 9r2cX B2 K$ 2/mGF 2u @m 2"d8 2r /)2$La 22A   2 S2w 2H V )Dq?&U29 $ * 0 $2b 1#VjU&_ 95>12~#{+z^ = 2e LDv&> _ U 72S:)]*2J4 Dc#;2@H]( 2:YaOY 2@d  Jm2Hj`T 32Zk +B-= +2peJ= <2Y9& Kt/&2CqZ\*y2B ( 3(J :y! -2z m6#yh2u M V g4VP 4  t2_:'$/J %2 6![Av7uMKv2q; 7 { 'J 7vw2@l 0 xB+,S 2"  wrc $2 |R  8  62W o0 gs2<cb$a(!  R 2lBfZ2 AH %f2U  Bl522l9 0^ M bj2dN@@?ENh@W2G'P# &2V+ %d[2 ~$ 2 ;d \]2  Pr~)% t2*M'Q2*( f/]2| 6`eF![8 (1& "2 JL(|2 ~M95Ck*W$ $2e1 ^1&1(0 d0 _0  '0&/ j0 A600 0  )('&&%%$%$##""!     654332100././-,+,+*)*)(4'&&%&%$##$#!  6-5544332211/00//..--,,++**))(('&'&%%$#$##"!"  65544332100//./-,,++**))(5'&&%&%$##$"! ! 6554432100./..--,,+,**)*('&&%$#$##"#!  6 5544332211/0/- ,,++**))(('&%0$$#$"!"! 654332100././-,+,+*)*)(6'&&%&#$##"#!  6K5544332211/00//..--,,++**))(('&'&%%$#$##"!"  65544332100//./-,+*)(7'&&%&%$##$"! ! 6554432100./..--,,+,**)*('&&%$#$##"#"   655443321/0/- ,,++**))(('&%2$$#$"!"! 654332100././-,+,+*)*)(8'&&%&#$##"#!  6"5544332211/00//..--,,++**))(('&'&%%$%##"!"  65544332100//./-,+*)(2'&&%&%$##$"! ! 6554432100./..--,,++**))(&'&&%$#$##"#"    655443321/0/- ,,++**))(('&%4$$#$"! !  654332100./..-,+,+*)*)(:'&&%&#$##"#!   6"5544332211/00//..--,,++**))(('&'&%%$%##"!"    654332100//./-,+*)(2'&&%&%$##$#! !  655443211/00./..--,,++**))(&'&&%$#$##"#"    655443321/0/-=,,++**))((''&&%&%$$#$"! !  6554432100./..-,+,+*)*)(<'&&%&#$##"#!   65544332211/00//.-,,++**))(('&'&%%$%##"!"    654332100//./-,+*)(='&&%&%$##$#! !  65544332211/00./..--,,++**))(&'&&%$#$##"#"   655443321/0/-=,,++**))((''&&%&%$$#$"! !   6554432100./..-,+,+*)*)(>'&&%$#$##"#!    6 5544332211/0/.-,,++**))(('&'&%%$%##"!"   654332100//./-,+,+*)*)(?'&&%&%$##$#! !   65544332211/00./..--,,++**))(&'&%%$#$##"!"   65544332100//./-=,,++**))((''&&%&%$$#$"! !   6554432100./..-,+,**)*(*'&&%$#$##"#!    6 5544332211/0/.-,,++**))(('&'&%%$%#$"!"!  654332100././-,+,+*)*)(A'&&%&%$##$#! !   6-5544332211/00./..--,,++**))(('&'&%%$#$##"!"     65544332100//./-=,,++**))((''&&%&%$$#$"! !   6554432100./..--,,+,**)*(*'&&%$#$##"#!    6 5544332211/0/.- ,,++**))(('&%9$$#$"!"!  654332100././-,+,+*)*)(?'&&%&%$##$#!    6-5544332211/00//..--,,++**))(('&'&%%$#$##"!"     65544332100//./-,,++**))(2'&&%&%$##$"! !   6554432100./..--,,+,**)*('&&%$#$##"#!      6 5544332211/0/- ,,++**))(('&%;$$#$"!"!  654332100././-,+,+*)*)(A'&&%&#$##"#!    6K5544332211/00//..--,,++**))(('&'&%%$#$##"!"   655443320&  +,+*)(2'%&%$##$"! !   655443,  ,**)*(' $#$##"#"      6552   K %*))(('&%$$#$"!"!  62!+././--( *)(? #$##"#!    65%1/00//..--,,+(('$%##"!"   6, +100//./-,+%(. %$##$"! !  65 (32100./..--,,++**$  #$##"#"      612321/0/- ,,++**)1$$#$"! !   6*&4332100./..-,+,+*)*)A#$##"#!     6$-4332211/00//..--,,++**))(&( $$##"!"    6#.44332100//./-,+*)(( A$##$#! !    6#-443211/00./..--,,++**))( $##"#"      6')5443321/0/- ,,++**))(('%-$$#$"! !   6+54432100./..-,+,+*)*)('A $##"#!     63 5544332211/0/.- ,,++**))(('&' '$##"!"    6154332100//./-,+*)('&@##$#! !    6!5544332211/00./..--,,++**))(&'&$##"#"      615443321/0//./-=,,++**))((''&& $#$"! !   6$554432100./..-,+,+*)*)(F'&&##"#!     6' 65544332211/0/.-8,,++**))(('&'&%##"!"    6 !654332100//./-,+,+*)*)(F'&&%##$#! !    6&45544332211/00./..--,,++**))(&'&%% ##"!"     6 65544332100//./-=,,++**))((''&&%&  #$"! !   6,.554432100./..--,,+,**)*(*'&&%$#$##"#!     6 65544332211/0/.- ,,++**))(('&'&%'$$#$"!"!   65654332100././-,+,+*)*)(F'&&%&%$##$#! !    6(.-5544332211/00./..--,,++**))(('&'&%%$#$##"!"     665544332100//./-=,,++**))((''&&%&%$##$"! !   6 554432100./..--,,+,**)*('&&%$#$##"#!    64 !5544332211/0/.- ,,++**))(('&%$$#$"!"!   6+,54332100././-,+,+*)*)(!'&&%&%$##"#!      6".4544332211/00//..--,,++**))(('&'&%%$#$##"!"     6 5544332100//./-,,++*)(2'&&%&%$##$"! !     654432100./..--,,+,**)*('&&%$#$##"#"      6 544332211/0/- ,,++**))(('&%:$$#$"!"!    64332100././-,+,+*)*)(F'&&%&#$"#!     6J!44332211/00//..--,,++**))(('&'&%%$#$"!"     6#44332100//./-,+*)('&&%&%$"! !    6"432100./..--,,+,**)*(&'&&%$#$ #"       6%!43321/0/- ,,++**))(('&%$ !"!  $    6/4332100./..-,+,+*)*)('&&%&#$ #!  #   6:332211/00//..--,,++**))(('&'&%%$$"!"     6 332100//./-,+*)('&&%&%$ "! !     6)232100./..--,,++**))(&'&&%$##"    6$21/0/- ,,++**))(('&%&%""! !    6 2100./..-,+,+*)*)(#'&&%&# "#!     63<-11/00//..--,,++**))(('&'&%%$ !"!"     65%1100//./-,+*)('&&%& $#! !      6554!/00./..--,,++**))(&'&&$ #"#"      65542 '0/-1,,++**))((''&&#$"! !    655443/&./..-,+,+*)*)('&##"#!      6554433- /.-#,,++**))(('& "$##"!"     654332/-, +*)*)(( %$##$#! !     6 5544332211 (++**(" $$#$##"!"      6554433210/"%&%$$#$"! !     6554432100..  '&&%$#$##"#!       6 5544332211/0/.--%"('&'&%%$##"!"!     654332100././-,+,+*)*)('&&%&%$##$#! !       6-5544332211/00./..--,,++**))(('&'&%%$#$##"!"       65544332100//./-%,,++**))((''&&%&%$$#$"! !    66554432100./..--,,+,**)*()'&&%$#$##"#!       665544332211/0/.- ,,++**))(('&%$$#$"!"! '  6654332100././-,+,+*)*)(F'&&%&%$##$#! !    /65544332211/00./..--,,++**))(('&'&%%$#$##"!"    65544332100//./-=,,++**))((''&&%&%$##$"! !     554432100./..--,,+,**)*("'&&%$#$##"#!       5544332211/0/.- ,,++**))(('&%:$$#$"!"!     54332100././-,+,+*)*)(F'&&%&#$##"#!     -544332211/00//..--,,++**))(('&'&%%$#$##"!"    544332100//./-,,++*)(2'&&%&%$##$"! !   4432100./..--,,+,**)*('&&%$#$##"#"      44332211/0/- ,,++**))(('&%:$$#$"!"!   44332100././-,+,+*)*)(F'&&%&#$##"#!     I4332211/00//..--,,++**))(('&'&%%$#$##"!"    4332100//./-,+*)(2'&&%&%$##$"! !   32100./..--,,+,**)*(&'&&%$#$##"#"      3321/0/- ,,++**))(('&%@$$#$"!"!   332100./..-,+,+*)*)(F'&&%&#$##"#!     32211/00//..--,,++**))(('&'&%%$%##"!"    32100//./-,+*)(2'&&%&%$##$"! !    t8mk@~|zwusqnljheca_\ZXVSQOM}{yvtrpmkigdb`^[YWURPNL|zxvsqomjhfda_][XVTQOMK~{ywurpnligec`^\ZWUSQNLJ}{xvtqomkhfdb_][YVTRPMKI~|zwusqnljheca_\ZXVSQOLJH}{yvtrpmkigdb`^[YWURPNLIG|zxvsqoljhfca_]ZXVTQOMKHF~{ywurpnligec`^\ZWUSQNLJGE}zxvtqomkhfdb_][YVTRPMKIGD¿~|zwusqnljgeca^\ZXUSQOLJHFC}{yvtrpmkigdb`^[YWURPNLIGEB~|zxusqoljhfca_]ZXVTQOMKHFDB~{ywurpnligeb`^\YWUSPNLJGECA}zxvtqomkhfdb_][YVTRPMKIGDB@¿~|ywuspnljgeca^\ZXUSQOLJHFCA?}{yvtrpmkigdb`][YWTRPNKIGEB@>~|zxusqoljhfca_]ZXVTQOMKHFDB?=}{ywtrpnkigeb`^\YWUSPNLJGECA><}zxvtqomkhfdb_][XVTROMKIFDB@=;¿~|ywuspnljgeca^\ZXUSQOLJHFCA?=:}{xvtromkifdb`][YWTRPNKIGEB@><9~|zxusqoljhfca_]ZXVSQOMJHFDA?=;8}{ywtrpnkigeb`^\YWUSPNLJGECA><:8}zxvsqomjhfda_][XVTROMKIFDB@=;97¿~|ywuspnljgeca^\ZXUSQNLJHECA?<:86}{xvtromkifdb`][YWTRPNKIGEB@><975~|zxusqnljheca_\ZXVSQOMJHFDA?=;864}{ywtrpnkigeb`^\YWUSPNLIGEC@><:753|zxvsqomjhfda_][XVTROMKIFDB@=;9742~|ywuspnligec`^\ZWUSQNLJHECA?<:8631}{xvtromkifdb`][YWTRPNKIGDB@>;97520~|zwusqnljheca_\ZXVSQOMJHFDA?=;8642/}{ywtrpnkigdb`^[YWURPNLIGEC@><:7531.|zxvsqomjhfda_][XVTROMKIFDB?=;96420-~{ywurpnligec`^\ZWUSQNLJHECA?<:8631/-}{xvtromkifdb_][YVTRPMKIGDB@>;97520.,~|zwusqnljheca_\ZXVSQOMJHFDA?=:8641/-+}{yvtrpmkigdb`^[YWURPNLIGEC@><:7531.,*|zxvsqomjhfda_]ZXVTQOMKHFDB?=;96420-+)~{ywurpnligec`^\ZWUSQNLJHECA?<:8531/,*(}zxvtqomkhfdb_][YVTRPMKIGDB@>;97520.,)'~|zwusqnljheca_\ZXUSQOLJHFCA?=:8641/-+(&}{yvtrpmkigdb`^[YWURPNLIGEC@><:7530.,*'%Ӱ|zxvsqoljhfca_]ZXVTQOMKHFDB?=;96420-+)'$௭~{ywurpnligec`^\ZWUSPNLJGECA><:8531/,*(&#ͮ}zxvtqomkhfdb_][YVTRPMKIGDB@>;97520.+)'%"¿~|zwuspnljgeca^\ZXUSQOLJHFCA?=:8641/-+(&$"}{yvtrpmkigdb`^[YWURPNKIGEB@><97530.,*'%#!̾ᮬ~|zxusqoljhfca_]ZXVTQOMKHFDB?=;96420-+)&$" ͭ~{ywurpnligeb`^\YWUSPNLJGECA><:8531/,*(&#!}zxvtqomkhfdb_][YVTRPMKIGDB@=;97420.+)'%" ~|ywuspnljgeca^\ZXUSQOLJHFCA?=:8641/-+(&$!⬪}{yvtrpmkigdb`][YWTRPNKIGEB@><97530.,*'%#!ά~|zxusqoljhfca_]ZXVTQOMKHFDA?=;8642/-+)&$" }{ywtrpnkigeb`^\YWUSPNLJGECA><:8531/,*(&#!}zxvtqomkhfdb_][XVTROMKIFDB@=;97420.+)'%" ¿䫩~|ywuspnljgeca^\ZXUSQOLJHFCA?=:8631/-*(&$!Ϫ}{xvtromkifdb`][YWTRPNKIGEB@><97530.,*'%#!~|zxusqoljhfca_]ZXVSQOMJHFDA?=;8642/-+)&$" }{ywtrpnkigeb`^\YWUSPNLJGECA><:8531.,*(%#!媧}zxvsqomjhfda_][XVTROMKIFDB@=;97420.+)'%" ¿Щ~|ywuspnljgeca^\ZXUSQNLJHECA?<:8631/-*(&$!}{xvtromkifdb`][YWTRPNKIGEB@><97530.,)'%# ~|zxusqnljheca_\ZXVSQOMJHFDA?=;8642/-+)&$" ਦ}{ywtrpnkigeb`^\YWUSPNLIGEC@><:7531.,*(%#!²|zxvsqomjhfda_][XVTROMKIFDB@=;97420.+)'$" ~|ywuspnligec`^\ZWUSQNLJHECA?<:8631/-*(&$!}{xvtromkifdb`][YWTRPNKIGDB@>;97520.,)'%# ~|zwusqnljheca_\ZXVSQOMJHFDA?=;8642/-+)&$" }{ywtrpnkigdb`^[YWURPNLIGEC@><:7531.,*(%#! ּ|jhfda_][XVTROMKIFDB?=;96420-+*E^vu`' fc`^\ZWUSQNLJHECA?<:8631/_? ͝|b_][YVTRPMKIGDB@>;9752YuH>Cm ~|zwu|ma_\ZXVSQOMJHFDA?=:8666&$"2` }{yvtrpyb`^[YWURPNLIGEC@><:7F?*(%#!u |zxvsqomjhfda_]ZXVTQOMKHFDB?=;9G-+)'$" 7v ywurpnligec`^\ZWUSQNLJHECA?<:H{/,*(&#!'xvtqomkhfdb_][YVTRPMKIGDB@>;;0.,)'%# A¿Ǥusqnljheca_\ZXUSQOLJHFCA?=:1/-+(&$"a{rpmkigdb`^[YWURPNLIGEC@>;]20.+)'%" ¿ࢠ~|zxgeca^\ZXUSQOLJHFCA?=B41/-+(&$"+}{yvdb`^[YWURPNKIGEB@><:71/,*17ȣ͆o|][YVTRPMKIFDB@=;S20.+)N ¿⤢spnn\ZXUSQOLJHFCA?=:1/-+('h画trpmkfYWTRPNKIGEB@><9a0.,*'%#!#+)WXusqoljiXVTQOMKHFDA?=;86/-+)&$"  wtrpnkigWUSPNLJGECA><:P1/,*(&#! XvtqomkhfyVTROMKIFDB@=;90.+)'%"  ¿ﴩwuspnljgecUSQOLJHFCA?<:8^/-*(&$! ߯vtromkifdbTRPNKIGEB@><975.,*'%#! ƮxusqoljhfcaSQOMJHFDA?=;8N/-+)&$"  سwtrpnkigeb`SPNLJGECA><:7}.,*(%#! ڹvsqomjhfda_ROMKIFDB@=;97a.+)'%"  7йwuspnljgeca^hQNLJHECA?<:86:-*(&$! |BȾvtromkifdb`^RPNKIGEB@><97I.,)'%#  usqnljheca_QOMJHFDA?=;86z-+)&$"  2rtrpnkigeb`^fPNLIGEC@><:75;*(%#! sqomjhfda__ROMKIFDB@=;974t)'$"  4=~rpnligec`^fQNLJHECA?<:86E(&$! h}omkifdb`cRPMKIGDB@>;975vv%#  ~|znljheca_TQOMJHFDA?=;864hB[" t}{y}ligdbaYRPNLIGEC@><:7537*W)DF|zxv{}yXTROMKHFDB?=;964C+)'I_@46l~{ywurpЀWUSQNLJHECA?<:863s*(&##kԁ}{xvtromkon[YVTRPMKIGDB@>;9752h)'%# #FfqpR# ~|zwusqnljheca_\ZXVSQOMJHFCA?=:86415(&$" }{yvtrpmkigdb`^[YWURPNLIGEC@><:753A*(%#! |zxvsqomjhfda_]ZXVTQOMKHFDB?=;9642s)'$"  ~{ywurpnligec`^\ZWUSQNLJHECA><:8531e(&#! }zxvtqomkhfdb_][YVTRPMKIGDB@>;975203'%#  ¿~|zwusqnljheca_\ZXUSQOLJHFCA?=:8641>(&$" }{yvtrpmkigdb`^[YWURPNLIGEC@><:7530o'%#! |zxusqoljhfca_]ZXVTQOMKHFDB?=;96420f'$"  ~{ywurpnligec`^\ZWUSPNLJGECA><:8531/0&#! }zxvtqomkhfdb_][YVTRPMKIGDB@>;97520.JQ'%"  ¿~|zwuspnljgeca^\ZXUSQOLJHFCA?=:8641/-+(&$" }{yvtrpmkigdb`^[YWURPNKIGEB@><97530.,*'%#! ~|zxusqoljhfca_]ZXVTQOMKHFDB?=;96420-+)&$"  ic08 jP ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cOQ2d#Creator: JasPer Version 1.900.1R \@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP i߁b[׻TQvF-5Mx]a i;*I:7&ָ&?gGϴ+m,K7KqUI>:X#D坮7=W0bGdn֖_߁b[ÊZ|u6&/uR7WBNv2y}߂rAsC(V_ CҵuhY= Y=2u.1nQPV$c)O;vJx(ѧ.x^}@i ;b4T; dtpb= M|4v{QQS/[ЊpK ]p;q v,&oy->y;vB|B -B>E{\%IAS:QvbBvru!ܣ w1ʫZS.b۠%٠(ҋ]aOatMΠ$lͲ(<]<%D9̍<m%qW{fWΖiP;|KO+-W66^r|,_ !<x?/s"Lװ^ӣ9 tʂ$LP9(tqg*[ЊpK ]p݅)_NuU>Ҹ Q"MչI,ZK"m$]*;6B"v32 EC_Y6,%`֤*C,"rB P XdV53Y5 k#I T%NDDs;-^U 2E+Jq:v ]xOhG1; $ˈ2ɠe&8Ouh:84TԘC[)R&}"YSZ=7u%OY0_Hasʌ ھI`tFD;h|v7V=w~6k.!{L;;0¶K?:-b?dB0֊Bd Q:Ubp%~U{_4vh(:ܸf9(m_@Co ʳ(>j&J 9y5N$&aIS'vJC7*%HϤJla?~шn vǦq I2ÖGz߉3 n{>mzi s} f54%ڛ}H;. wHIxsa_%}Ɵ6Ѥ!#HfV>gXN`v扞ZlBocsʉJ<_uh:84TԘC[)R&}"b"r)E[P{^mf6XWwY)%EP`C|NN,D/ӛuKVߝ#? ~thJ_н+q2;:3iSI8ŐKUǢߕ@H{sׇRBZo^ˁƺn@X΂{=OҨ}úGLM~M;ܑhzKSʯǼmܿ:=o¶HHA 83AnEE<ԫ}Vxl &#fKڻ!EL1 UܣY"h`P/|@ѓG0NT>BudhpN 42߽k`pS{^Ȗ#a!S҉*)CR q78) =: i_^'4kǕWR(l_q/w8 r1= m?o}}Z[$Q@$lLy!ֱv-qE lNSS҉X=s݅s ޝ^\;֏O-F^,q;og:K &q"6 =H=%cPsc)5 @0{ 0zpsG1Omn{wpMHb.;/D=`]Y&v,1@]9Uۧ9ptXG'eNgbe9bJ^'Od;G{9LU'[އ?K`z1S;}ȥg *=N͞uM/b߯y^"oaRۉY?_.EUIVƓ0IP])qaR:(3/y~JXjHo!oY e9N~ ]rƱ^7FVk]"I#VOEȰIRQw"F┊ &6*k|r*UP[iJaiQBnWȶ7|7x0n2m{>xi9340`+@o,TVTۯ=sǏh0 t#Nply&Ò(u_G<;?'=VVoqh߂.X,T\3&%Rb>[Ugf 8^x{f${er;#~4D|0aġ|LF(`! ܠ3 n?}PhKe vzwpyLjkmt :/ը"Z,=anaXpd6Ő7r#dS '7 q7RQC_ #ẕ|#]lY /n2gpfpR\H`b]BDȿUS&2/Yh&XًcJo}Lͧ:yO:a@6(SMlcL@|%G&. ll;''ySDt/ wj=*Ǘ@~:J̸Ov *ޏsS7ꖃAG5\[y~cDy3á)n~bԸ >Rs_͆W00f=}` X3WPׇm!:FpE&0d"UR" ~@1W娟\,!y3?+Z 10kw࿡*IzLp\znJH@QuxwdN! W|u)Q8{Pi\_i+ΐ@8IAr]wyLCģ} (L?-i]CQ |Z~vPi, FǗ7|H^ݖžs\,gϞ471lp8e6̑^L]* 0E(A}\_ߡ1e 4k_՛4r3,rgDvh& |sX ,8Z!ܜ#ˎ]W'R`!B٩k1=t,J뎃塎oA}%)ON6RDIV|R=H^GÞctkު㫑dVE^\haK^k Ҿ>۸ l׻Jg\3z4G~DWܠu$JێYuz=^3Viaם]+55e4 TjRջ b<@;QZ|#׶GO'h7Wڎ?^bߜ>U4k3$mb inUJԏ;`mFeҶ5;A K |ljSY.eވҽjUŧ"!t(tt:J! YV u 8"9|9Ҍr| |viHo!~;Y*tL6*σ<7S~op^_}=іɏvZ^bu`smqiH Zmqʼr2FzCҒS;c=bfՃ]ļO%Z(\[??y/*;u6C:̑ *|$OcwV_H}Z[~?M>/\wޙytNE7moh@GaQp~3]bvJ)5myG3͊A<2\l=V|9^O`櫿@Y}VUkIPRo!N]~):TG TV(!6z~ *'P`Ӛкo"! jȻl(`.ZZdvΰrʑQ̟SJB=^5,.TJp'o@X"֙].wPE]XNzIPeۯ\~qWcBI&iڣSHm~R AC׻dS9,6Kl3r-bOsf]|DAYmҮ@3aܑ xBk=Qjc)oOW qCMԣgd{um;#^)k!ܛ DUҥ ?' za e- ~l{y&;o6*N͐.-7ZCьf !$p?a]f1Ȣycݪ_l*rͮi θ+mV2Z.ⴠKM*EB8^x{f=޶1KxMƸ-__0aġ|LF(`! ܠ3 d.xUp*OO27\G#yڽ+Fb IE7g' ̇M82N.Ur"닕XpLT˽PHjΨg1dLɘB`ưbf(g< ATXX'行 A1Ä*&w_j0yqcΜP76 `5!Kk5GE'17r,l%yWH!(]&fJ&@xqú Ve`4QŶU|!FY^&N7V]Z.b^5;.^EEx)KAn.1ƉH (ߞߞcb]Cx_FLmu<"4aNS!IUō,rQoSE{2y(c RAl)=$/L)u*Pyi͹nkLw0/{]1oG9X +[T?[O7WVv,"2'̇pPyy/T烮q+FƗ/f=_a썳* PW<<4UQlRzUkvrXl->n|gE-DB_LPM }z)@(Ev/ BFWHw3܃[ 2ncb;!C)(*4wrݩi$7r_vbՔj7γXG oQu+_08ԅ4N2\swmEEa}ߌbpC B9FP5i,13\j1'BY'5{r@!€koyRw8e$1 XDU} ;Ow X ӗͤۨ/*Dž+<%-9Dkn@}l 4t[OBSY|0Y49,šXPzz>F~ޜ\*bfXe;KtU&wMI6cBÁA?Fa /+6 FԨ8ʖIkfQv:z)SQkYROi#K:axN"8ERm+L.])H\͏R"nӮY8صIk=BL\uw)P(ȏs+i]ۇҳq2؇Z?tYxp}z {:-p6lqfRr(/Ԃ9>1 ߷7pE8,1F<2av#t)!re-W^gA=)Pz=HQ:5lBD7{1tB]dW2M!ѽANtɝ0S 3h]_ݯipouHЀ^)mwo9YٻAŲSXW-_`x<$uL "f1Rk4Xs֔l8VᖾlIQK,JP6V? lE"쮋gR\XFw{l0HܖMLђ'~4.*"dWq& agPE_khgJ,?l't>SEg X$ H F"Tz;Nm!Э8_]N<.J2ƷLq܁,PkV 9Oa觽kٲ&:0~vC56S@3?i R4=wiz(nѵט3 5@Q\eR7@SJ<ݾq8H=`N<_VKUYh ˘w5缽o1L f4 m]J S,{; [D+w$0R0]$okNihn.#UH!Bc/'3! W&l j4e=Ά^Yg]4Ym'X:$od~S/(*$AgFڥ%I;0ٗObC \)cN9cb2FM(_A,Halfri`kXZɳx$jMc^+lIj`U`h׍:z0waxA_'|V }:QZ*6S=)ZVq T*,G"C/ys up16fS;e|&$1@9FԊfD 4-%!ʚ3u^rǎߙ^"+Ƥw(iU-{FF!;T>/$,5O{錠PJ%ax Kd৾bvE;rF"JRF\2 `vItxUפsd=fbljY2{8-4mGtơ ski!l LEczFWܗE.|>".&(Ζl h(帗Hxs>iRIPӎH OueR5 ԞZk~5%4CϬCa:UaSJryA>CERyT9cYs\ a 1+YArϨ[@J3/` >1潮zUQ2Y[%@2 [sI[χm`~bC23BYku| Ey Ze8727/ E7]6Z&X\ 5Ǚ_@kdXf=S<:*%Ql㒓1 D Ĵ]'תq<%~:C͘~WvToV}JIG K`b*Rr&YcXJ#A7=r1=~=}4 @<*:tAnRlGj3Qh󸜽^d1-$7+ DIVi:nfBXcDv-+^+?wTr7#ĵ!wh}n]I&餓#uz`^Tr7pkQN=XKҫ6 䀉K]kt[=ܼl.ues)5PG)LɕKHH& cÿܰL~(w,UMX+Xڌ}Duϐ)F`79S'59lh֬N!67uc$[(qψh{x5ӧE'9dǽz=p1cź_顗`RHX"y{ Qf&:_v3^#ı`Z 1J K[tx5R2}Vtmbb]zlqpUwY bSPj9=wf'Y'T{Nŭy(S P@D}UāQB,pt14eMU%^+obt٣kNO#ʀ>z6s B/;ܓ VD}=KqBs RRJ{h\S*xr&}3?RŻ,R/*&ii8NþTͥ H7:_3 8RO]Y.!! g0tJ+&ͦ?M͆P+:W\oinAm!RGd7~gbp(aFluwǚɆ (w+m8VϾ Ո\Erz~gMU5e=)QFCjr}@ P{×v`%ȱ|́1qPmDoWH0n0UI:p/'<(OKPFnRʡpCHs׻-`N aH%5߫Ľ濫AU.^tRUANy$ΕW4qInoP9bcPtE/bo3o &40͙7g,be.!"83~k̕&(5?ׅBX٬R^IxRf}N|>ǤiI#샤Uoq+ ?h=O2=Գ\m_,;tl dW r.Ŝ72gn'o0 E,d<=ضlǀZ^!>wc_Õͤi cL98Bfhc)qU@, 5Q<5R>RH=ie-fs{Jˡʹ2cwK}>F([1@A onF3݀҆Sq.^B"}K:Wbp[ie(4ǕOGat/ 7lm͞U&fzU4'ML<7w_Ul@:G575@w/*piO3Ct~)lERE֥9g )Ά |{"@u粮K(W%_?ݬS Jz^t<_q^i>2Z`ўLVv|\$f?)α=(jSGǦZ~*akЙC1}siVVB{lN/2i"S eؖe<*fƣd\~]q/JQKDڌ{'1_b{.3E_M#Q} F"8 D([!F֪oXquadak㉏0`sLp]+>e>%@ =?FtER*3S} kO'ԂBf`Fj},1 ฑ2udp/ך[dXvU/ר,P ym\IXi7_4zZ`>[K_PU.ᝎu 2#`؈.V j\C:]~0bۻoȇ6&rd6;[s_΅6S{'O?WS0㇤I^ 0(kdKpV:qv`~ns@;x*&7*hw2!iEHn`K1piHco#A;G7Řm H%&u=NjYƓ\Ӛ@P:+c;eKKn\*Veiܨy@ycM7i|I]uGR ү >rB˭55 |Xׇg4< ߽~Z>0Iewnm&mim *d_>3Oܟ?W:A*eeÙ.+"LJhF!צ^-x֯0 7v}1KZcEB2OpM_# <)Ck, :J'o 2l:rr\-`r"\g;܋6<QyC"Ia=7= N`sG4Ga嶴:Ժ)1@$+,-r(E|(!-y$z@>bHޭ,N+ڡ'O7;Jt(QZ`$cF' F>o;-Urs]!|3튲:V@i>?UB2#8έyxiLG$j$aUΎ1srl>UpA4Pߤk7&R%@ܩ#T8i4S5q L*xݴAQ"g<tÆ5{7,u80PHJ_oG" ?4TN"Nb*P{#IyhY)"MxՌbGELCj"zX UU˄?Ƴ3Y,Vv8yHSBH9OiZ-3klo;纵 q&c!ۓrձyX QT63q` @mcY }`Q(GEj0`{rs-p\V)V9t]M%M#VInb)Xr{Fc 2@m76T;UsI͉Vƞe\ߚ@"S]rWƁ,|oygS%^Żi. 8qIR_W6/ $OB< uOO;hv%ik8D=~F.9o| et?xU c~m,2.r vK&-q{5딉^Hthc;ϫ^z+^yawaba*S8;˄[ÎAФ1^hCK!ʫbOR~0=X-'ip! kRUhce4,}cZ;`o!ȸݎյD.q2fr0K }\~G+lZ3bs!ВSEg NJ$e&ύT y_҄f}7̚嵐wJ4u^zq(2$=uLRC'8WE"JlQ\╺ 5gX9#QT<}%-.fK!dLإKT\x*I?rD#jolWܫnZ; fHZ#[}"ߘt.;,☁X#0|+%繽U:ҧU,B3hL,HV5u2sL4R%/dKhkٵ҄ǹ۳>J{VM2'm54`Rʪ$`!1ݓ^}]E9eԽNmԠK=)<XɎD] Tx n6߯uv߶z>4AR%i6KpګqG=[2tktz~z-,ҫHoki[̷jp3gQ N.Uqᬚ"NΩ*{/ZOVң/xRz_#]Ɓux6?FfG9ogq;˓)jH ~E(17H!L3^qSS'lc`dC p|i_d 9^|V/)[S Y)!{7_/{uۗ ^utm"6 %jat6ߣL9%5m ڗ7uq>([dt=4iWM渙=? Gk^L- ꤒ *۴NG5B[YPCER&:3FVTΤ&t.Z'D-h<20˜S-v֞"JjXT2oGܘ.LˊgA]UhGKKr,a;݀d%> BE Dn-\™|>d_tW_;j DJw{$='+3I2Ӧ\kHL$-:8WزdO$n۹xZޱ:"QK\S㚤h5Me h1ub*kդy,P=I:jШ#PKVQʝb*zð@[f1L;˽:؟JhV(#hM:ӄXtA! 9Z ϼq1,C˪ŏqgaW o瓣ž@-xz$=A%_ J`xMErpQ 본@Z3oR_SY7y{XzA-#,tެA4f/FWN9~ReZO2OJ_|UT\ d=qi )-#`k`( 4鵖^b.-cp뫌@ }FTʿ8w0Vp-"1 2@|(Waha~FE fPUk AB5YCoDÚO_K*$hp1w͐XG ZX ^``؞^Ζp0 Ch꿟yMd4~l6}y˲35+B~%9B9i;3/4 fZ1by@nY( IjݘNF@)*_)S5*6̌0㖩&0{B <f^ ܅&mZ`:h2;h"@ 3%eA*U֥k+1MHﻅSaT')JXH|=@TĈabcQ.EV |n֛_ރ~M\_xdYną(5D p6a:(ߖv_:@B{rf%;Pڪ8@~OSxPkw P2gn'o0 E,d-ّͣjCwZA!@0AKP`Ɋ\DK(lE Wgwm5%BPbO@Z.\b7ŮאCH@3aOn JS|JC nrJj LPeQr1)B312I8-ھI#u| 0Ew"b%Ϯn, l\=86Й\8TIb˧Usip)W2HțēM<70PLnpYk>`XhSH- 6r[dI\1[uᓈt%V@O[gGONY槛ѶGH<tJΛnek3:bffɛh{ʥ!fscc*h׫ rͤ"ό\{€R}9 U. ~ֆV [F%$e$aHm2QA=.1Į^z8m''l!w|]\heFk[`ck11ǡ6F7Z Յ[].b-IPB5E/% =Uc3W/$mtq{O'by`}jBua$2f_u%n̮CıZeb+_5ܱCѧSkG>ϒv3WZBq_GZ".KJRgndb&e \%`/RN:Y^# c;f;n֮9O蘦{1mMZswAG\]~egr$2|82KzȰ8gA\yNޟq"Se;WLܽTi8ĄAWմ7`il݋9{ X%q+ol,8SLc/J\pM11G~ƥ$ZQM؅f=@D-i]/)c;{Ra4[|xEҾdU5S YThocMQ؋BY_.4 m[ ~"q(>P]W+ O{ր׎cBڮh?A*R7@][Dx0j 5Fz#LxVǹw^CjTػBc2n4MOXf-d82+l)$e$*!}γ_ r.`O9֪>Pmh?=ܕcymK!$Fw.AAұ10DW6;&?&=G%ks}7`{B:uEFvmGZ1_"xNzivt))@plַc`Uş.'kHO/bBa8{1h,k$y4 sSI['3i _@X_]eP??{1NyZ~iGed S}nP߸>'%҃(Qi#{l4Y\jj%T3!jT\Ch*^Ju/r+]r.hK#JI:b@eo)!q̞]gAhXW u+_Q=$ٽ5B.W[7\U<26ac<0`y_7ȣko XhiG LP?27P @wOe/P "gz}~5S2|@˷/0 U} l 4D_O҈UZ N;p^݈ӇkF_r$U Jixs( ( [ULi Ynq<lx5SֆXx ];yi@WLbBΰE־"wV&-iT|~7o9͑`?Q BRLj1َsGrګEDxt;RyW⼋':gm6"ZnUV ׽ѵ 2/-!5Zuzk'~EX6I٠, )jy|+Sr\5?gT4>|[VRb;>ǎWW?ֵj7a:jQ DROyR_18Ő]o@͑Ϡ7({CP8f)id] O,6}fi LGuB(1,֡O0Խĺ\L1>UZOթ/.%vs-i |f("3'9JpLii]T҈WjQ(M nmѨ- cܘj;|ţzc M!ǼK82!L24kA\I\8JBeɳce7zꧠ1[GuvW:~EzSgrBNB7Y)nI|Dmu M׶OI2^b;F"(մN 5SbT19-(R+桫Ľ̏"nvSel?fFA'd aۦKԋ&d80tcƠ?3-2@IoNRՃ9q~>7U21^&"瞟zG'뭧)7UgR۾*TxL5B֌JMٞ]%rO#z4Ir%yu$yc[wx&SKɶT{SDG26NjiYO_ F^)kIn}9L+x,0ÐS_bov} vpC6l(vIG# DC7.mD*csMkXmX>xw 6ȟZ)=2(4ň|?XB@g%~,:G1riIF1uUFKc4 u0.O@mSHd[Mh2~lI;L-3yEVl줂iII洬oT xЭRQ`,0S'-V{4D$btg^N+@VVu"TIJ !&:J{ gP56Fz('d6d,KXS"VVq-F-GUzr$WVqɥҖiyހ\iCk&' -uY$LֶYVjd:{Pwo֕/vS.DC((؆bEA(tcZM:;F!n|[_";zv]Q$pMuxqK aƗ5j0⢄ kJfJf cG~H Xېś< EA|mbꓤ)>3%{h763P%Y/\! Ce VgoBW*>E/3Nhn뀅.ėyqUw}խ&.z$m>~5Nո2mBgXY#TaO?, Y%HQJE f 7-оvD)jI_cL4@KIe<ڞⳈ`,ġF`cx]i.5l " AwzI 2ƆHst_%$!?/> ^mҀ 8M+j+m'FOz8&@e{KŌ>q&1#f4t~gD'GLsr+Gn1OI=XXUEWwg{E U:-Q[b"n>`7\\}{[孯/ l}r7ҵ$Fe; pDY}ZYMS$)*W)}7BGjwTl4`tQԝ\6+P$Q'q[ݐHY=OV& QTl>?_燨ģCse @r1 PId_S8! 1s m YB- ǯHRs\ؕ8])V`Avw0s47zȭh^67W- Ǯ6QcKp[>S<|Euc8m12Fڴq ۼ b:>j ,>Z? %vFrKq[b#!1:CPd'}EsT@Ξd`A{C,zse(zYa< 1iCw5b 7~]=sxdǩWO{do!!HXh0_̚"t"+}9i8V0QDA[~Vh~DA}bu^Lن~읯:c&T܍Ce.>Z{V avG,5-gJ7yvdv"ݘ*/YjPYBfy,:uM$D&c! ERs^݂U+U#.:J¿YNLdzmWҊ, }Cm^A]S='uK` CSi Aloյ6r6$N0ZX2tIόM3B n3҃Qw7 hij -2RK1^szyi*Hx'[(3)x͡6y\bշ(Q`#~)tJ5y (a^'^ìJv6(cf[.]̶\腒"cOĨ\;{c=٦ȔXXGQrfX/*\5SUp3NklՆxZIsso$D%Vs[YbOdczMT^سSҍ ku Dh]ǃT89IюH۔tWͿ`|d r z\;S^Wˠ5 U4IOrÂ9ZѰp?3kWh%uPA>n-y_fY!LUJ6C -Q7#ܴf.}rp*UD1Cjud={-ad0LLR,\?=I(HTN^ۢ tܲ!u' db/lHL3}Bȇ#.f~Be4\'Fȕ꾌 +WBF2"Gz%- ۦ^؟?:0ARk',(PUu9h …;v_\C9M[^-;1!(B,l:nFd&_}<=N:,/<K1 YggW6_Uv;k#lAGb?~ (q?(L"@_y:C:Hu$>pjSHEu$f}]k2s(ڦTn}FT"B;a{1LD|.D\S{q X׊V%X>88x!oKc5i!N`َ=RY=3qvRwjG5\#^Se<5Q% TҷaX].!Lƪa~*pp%d4ȱ4j lB4#K曊)0yBCCF/Ѓ=uA ŌjҁNSS_Zhhv8%,y;΋#yGշԊ׸ 2Wm#ؔtO5Wby.'i#៼uk ptJ%/JTl+djXպ$YVzX*+RXଙH&dBk4&A1ixHk].+[,PoxX¼&ِD&a7`MQ tHQi˭cauW ʆଘumȩ-_s+YZ'o@TL.V\4v/o\qCQ[k$M| `wH}Z '[ oT؅h3rM\lIzl |xqĂHRkʑ%rr3cl~\hQ6paGf^aeYm2h "(gf:hJ{~bk&D!Q#R)TZJ$z{, q!A׫(9$5l;8B#i{ЩpZ>aK+\Jy Ē;VLWYPCgP/֍?E;_ [gP>Mm.SQH'$9:c8 (D9L} ;[mud=JJ yZX=Eʚ<jv]ۨ[Z;l{~1wbc,S 蟲~EZwqJ?^8y̗4&U G^Df bjRMULoN 'sq_f.@xq7RAW^:!)dRShJz9 ]9``)n(-d5v$PhQxYpp? R ߖ<i! !QɣĢL ^G3)0pEP .>uԓ̇Ѷf&(%he5O-ؠYX3M#kLx9mm汋r\*c5Ѓ7 CX#|KN[0arcW޲!ZNgBc=W v_*%|}6hWA~Y~6~#"2lTbk Y(XI`֘M'hafJr՛:rSA(ŀlCNQ@+ G -R.@WW}hlyDa/%W좖DeHzϻs A7KFct1Uzd_3lNjQ "D๏QjEx+0z{ꑫLBfN}!hPՉmmfVTKEwU9R]o'M*ZK;It 1eꛛ2}kP!Equ, 8`bmcuPlRR*f)}G蜶BTď?(-/v-mhsvf ؔQ&{+ wc3 ـs:ߊ1cJU7?cfI? l8`/~Vߵ;[ J16;+OeC/Q hcTIƦ%qB_MØ<͉xӺ{@JGC ǫ[yI`!U9DˁP K'ψugZ h<#4DQ2ժ>-0[؋d+?5sd"A+k8e֯Q9g ̠ \eK4\]6 k^-&5WUkgl50@X8x bn(Q={ iS *Mn=|qM*z]|9=sh.S&piq&!zdqCkҠ'P8!)/Nq^O>*paru쮨jy0,YmٓLxcqٲ~nN yɺ'Y (XY9bmlPWDi9z*S@ƳqmU \lsNM?J!9Hu>W{C^v`7>]IvI34}nut"F>3[+5UEJqmi;@s ].tf A8s6on:PqE~HXv# 7 FF7IS%2?K 0d()$ .J5(aM^m\3ɟ6yT<_RphmxmBW=$ZM' /d9"1@:# +DoW(S^_V3'jo[mFHS" L1y&A wsg*DGH hTu+)CbT_>F9>`C݈|o81xtHil 6L8T<}pG27u佮<]-2Y+za0I ȕٍFٚ/&/P4E=JK*Gjw!'FW[d= M;W^#(5TUyH>P+8])S<·o @: zކp}||?RZ7ObTBϚOhU-q;iS6x'A!keD/վ"y knTrN u, Sj%򇆛Y=18FpJ5;!4n-P)h)ymt4r)۞ -я&8؆MlΆf|#E$N}ߢw CD#AzW`CvT#hd6bd(l?̆OZs|GKxg2z9.2kao:g)2&ۘqgwžw-5Y#}Hu<&.8A!cB==J;ty!XMґH~`Wǿ.o:Yj⠸[ٯjwNoac&X pjFPriS ;>o.qФ]+g^MTҬ{85{{ _HgQBZ];wQ@W^쵬qԋ6'>"ut42'qqH'X AVWJz䈸z~4',$'lQqnSG%CoKR$g )JNڭ<* sxq~ሽE$W܂ '~j` QQ6(97zl,(Nlj՟c˔ό)-砶c0aEp\ =a!AEX) 2n\F'H{3urX׍#3݀f!AdLѐJrj_ JH,vSOmy11"]"̄6@B(:d"C4]qj4 3>a!WKt|vΐȣGa+]PQlB]}[7!X/&ՕhZUI2Rޥ]aks#X(4~[6~̋Ğ E;=l9V xMeIfcc_@==OyfgYV#8}">dS)Ba=c }UA 3;k'0j^˼i}o~Tz7KFh/ig "[ *Y|"Pk .qP/ ]Ƥ .b0\4f[z6@KVU]LYd-JVFzhiA"ïAX]~XJYFX<+L6vM11tE2,nCKCҲlHk:Y5_m2/&(ҁ:F#"ZTQ+SFz@Կ>&RD cВJ}S?8Oybbgv? ,+=IxObfEs+lD;bIc.GLe`lKqLzn wkn7]u՘-Axpk }Wk+C~]*RSvgU$bj/G"/-{ XldC;6HlW(9|2F[[֌;IE* - ߼i[id,q[gX Upٙ Sw3ީ4 Vf뮀xpJl+e đlT'V1 @9F.<`z"-<0;~atqz). ؋Zf̈e}к8Gcpp1ʢ,df7Tt. tSfK[BJ{6 Wt+[(}i2D^nr8s;xpB?ٸ-?敮LM?o|iw 6!EF^lǂȧ΀Ĩj` #U US>AϮw{Y{P}^Ѩ&JSXD0Jr(1ѽjA0jEW{t@.%N; 8\o_K٬ _ W ќà94eKj}P1h=_'HdSIӟ:.-v2fGPBs41'H|-ufIVÅrC}yqf S7o|mm?p㈩-?AI4gpjhȪ@>/A9@;4ҕsDM$d09DC#t2-M ŧ>[2VWZtE,JLgQёO >4Gܕ#Z%*^7%din6z 'Fη&43Tߺ+>3̈́7W6 iHՏ 0)|I-Tz%{;)j/yH*ߨ'kxwtasѹMU])c:Su\$twYwTd0g6{L .2ZT30syZ~רP}I27zIg 6mh@d5k&7_k!t`<%#~ `qchvֳ-B zKc֤(C楄1?5d\19(yyD\ $M[؋(@* |U"Hb4"x[̵í RBeCٴ3ek\U#.2J1Nb8ѥohEՑњEp~Ú)􃿙JyCaKgqQI%t&FcFj@!C@$ϒQݭ4hޏSBjRnu4SLէ,L3DȤA۰+lf#&d&Dgh*}(q=M/ RRN{pkEhQ e;{Py \<%$6T5@3~Ⱦ1Ad*$~WP-q ȴRuk}=A4=IJF̑졾`~rU8-]+vR 6,ݚM7wЃFw=NBj#L"C<2huk~} 3N~rȣRrc'$ qF!dՁ$ ߱Rfr<]~c/j5F~i|\F/OZzl("sf8INӕ;v0gͷ]OF#[1JS6L֢d[C񢫬8;OboPUpg.~7'QӏL&?1[OȰI61׫Xpzo \k@UK i&黅B$oX#w+{#/h1!mDv)*?ڀ1ۣ•mAs zvh=<,/-L3JyGAUWZr- %*YMpް [ä@H)6ؼYY8gIީ݆!> 7dfX]#Tﭱ)o ϝJh@TQ%'zF7q~~y6?/ dIYܹ+$Do{}LCS+,"~e+ze0l4u渞$t$x#cR3-}^o*NYgQ8+L*q *;[;4ryu]18JgKNx2fٛ.! '3IKbJ+o/8_oL&jH 0*}9{TooVL=XѸl^AL'8+cZ3{9 :_æx+ģ74٩Cτԍʕ_*XvEN*tv;_c=+Uq,ivAbʅ":?QQ.v(Fzc`*jFO\:j{k#վSqgJ[֒Rg&s^rrd6ll? 90je?Xu3MbN*m3 c -ۥeУ\j)ϗZ#O"B`gMR1ϤwM<-=D2"8""Ѫ@B%cTgo'P[!'<\UNU\CP,n0QֵirIȬ,]43$(,D[yB'tä Ι 1nUFD㨀q<k%YOBtB+R*3n8U#$efFk5X;Xש?.F`HJJ`p Nw;'3d2}.0d =Z0(̗H=qfJ6"Y&TMv^:vY yyt-G\%qgV'}u؇߃46~d^ceƬ*2v(ek!>_ZKїƳuGp-qtH*yk|𢹼mo|tԠ_Ѡm/ebCA"o2M*OL!#@}6[ygRx\}qF yBv<4vh=qUeD~p~kS+e@ȥ6Պ*Mp`7AJéVUa{R(AB=H#^ܘȯ_diC$\MX-Q Pws]$ς~lwLdzp.9oF6@K>(J#;䌤km\ ҫVsiѾ2,]BU{K>s#NºDzT3Uiβ(<.jߊ^C/՘URE?NlTFk4 \F .GlhKmlE(Xٰ5|QZCBAaa'ГJHn [ԟvwd+!v?QO/&p!_3΍e֤?,';\辀}j#k<@$ǙobcRz7o$)8q²"L:.rQ]!Q0mN'3-7\9脙b|vI+xop{IT\gO.0i :iӑ=l˽c?ˆiu5J@ ?'BHYJ vލ!ւ*m9GA F?oBCudo^!s?-GX,ǍD2iv vi%&~,+<_zɉ*З4'7kH6U3*1VYC:ʽQIL.͜:|0hi9m@XoQ] iAI@bƀBB|<5Ž݄*iV[f0 ۿ-Cv 3G`zM]@uX0KXh$cHDB:U׹C+-.!7;c6O%<7>Zow5U|Ň-2ޞμ'd/d! !0QvGcp{amN_-K(\ka#V| qб.tU3 zQeyCAG CWn3%uB7wm(GaHvݭlEvHoJ.{dW˹佚@p/e=Z՗6f 4] 5BrXtbGNG A;ՍW}t2򈊃] W#^fhG6E>0Ʀ<G|-􂜏yLk&Lީ}[Eշ K fα c(g8w:L FUr7Н hfd{:Ԝ^#aQly$V<傉Ci|}BNœlsqNzq*|8ͥ C3q,X|mxԝk1 w>.8X%NklkKm4gB=GV@&A>KL E3C*#S05UԐtGK )| kpO k+Dͥ NZ)HCtZܳ˔ 5o?æG E V.{V)-/qӧ ~^{"f/-y1aH94 ,!G5\:3BoIj(L -]{DboXC0[h㫅,!Q +Y/ 9~f\u`zb&p y_GU#YZi] 5qs{sГ"Fs,E:zSK h%X- {5~"}xCkcc.Ks|171TUW-' 70ųjM%kbڡ3+ >6Ϙ͡hhYw?:sۧ)|V*(V'b)kcHRi{[+1T&xu_fNqy؛+7]|UVo0ZVW3iJO4h)ǼroMI&lT,0l T3R}~@ƴşkGMq}yΜe|.Md{2떻tS~ڒKʭ  I8a}NeR$xϰгfjeXP۲xc}C&j%^Jw1aoekM/嶒8S1'wnp_oo5u|Ǟ[~KpGO1!klwCU'=͉iղ~b!!ȷZ+m }_X[`Z*|r9MO5%IXnҠf|;.?`Y]5EkK? $&O5 ,$:1P:i6=&= g0mp+')61SqA, ei,,e7-55Vm%1yӪ490xAY7"PJjdIt8O/8?6>qnb2< ^U놄?lb~۽h;4XLH<~op>TՁnYg:]P1OWlogs+z&&-{kZ.$ICҟ=]g5Z3?ݷ^m٤2BT0\PO2q-.HQUx3jKq0fuzqޤ\Dx$ " E%\*R>QIy/sypށ85џu0I{2FJ'Ġ8J\_S [;(R l}pOm"SLGpOñ#_PZΠ96}h^wXI0*yO?Y2NBD2e !3%ceC4"JVSC&KkKQe @ڼұ KzwDU~;T8& M^`)x@ x;`( zt<CȻ6$&wH^ V^[yF3F[Q#  2zg(g?~R h4"9 ktw"1*z9hÞRǂco;ˑR}T,#qtV^Pd8< Iq+ݍ>M&)1(,@-Kk ˘6=%ȏA>k*"P`C8:~h!XJ(Rz"cqM&|XR]C,|,t {rk3 ScgxGdMg{u7t\NRgǁ=9>JBӶK:qhZ1hB:Pb03<,p/M;Lf=^`~~χOa81xhQ|*M{s0KK'NUj=4L"~wqqYi.osmzɢRl4Yl㙺+u~K4zI+(pyw\[4h|C#vFÃ/ɻ/tzu;j5Qe'IKP˃ /됋,qAyo/SUN[0Mw_zzhk5d ?0jA7.pϽohSxOcCŻi突&!3N/A U&ɫ3"wMێ(Jb$n˯~?N-omHTbkPD-]Br2g5(VDCCd~mljTE2{;HM79ұ˵TV,"ZR:t"hN~]ƞ[T`%<1 os?z&PeȌ2JX JmT49Ws*ܼ*tŴ>QnN.m3hW G`]@%y0֙f/G7M4M$.IYD?K3K@1y4+^H{*jX01x;q=z%Å&!y0)PXz0[_ Y' ;QN;S2MN 2iɚM<pa;,C#p3`K$t º}zy+6mJG57j7 6Y¡oP8k s֍fdR /n6H#/E( vc=Hx.T~Z,BZp U#5o7,p8; xnf@dd|5i_mrxWk4#M1)d[W*'iB] 1OsSfM4>AobY2|Abse~ذnX;Z;ެF> |h2F'f]p!U_,NF)B5 `cq.OB 4k~ө ,&~ph\YQИ.|xbtzvba 6ZgI>SaeOC +/7rARgee{Yn׮=%7) f`,bڕhSGBT$r~68ŸdZh\b.p'҆S~$R2<$"Qf)}_BߜTbjI+Ln'OKU=MOW׫ JK"T? ۰ֿHSTO{ܺ[j|1eaқGccKXsL2+ Շ~?[_?Pwo֕/vS.DC((؆bEA(tcZM:;F!n|[_";zv]Q$pMuxqK aƗ5j0⢄ kJfJf cG~H Xېś< EA|mbꓤ)>3%{h5UQ]Ih5UbfL t ~l?ב%T$M>odJ 8[яΕrm3 *.5wMJN:&SD4pI׬,wQp=rٮ=JWpV18}hBI9YfClq`C!qnw dOi _~pjb4Q6VlnÚe^7fsEbv}+Cп`A}6ͤ#B 7G9\qDEuvEkE rf\\t8(B$ǂC9O{]znW[b#!1:CPd'}EsT@Ξd`A{C,zse(zYa< 1iCw5b 7~]=sxdǩWO{do!!HXh0_̚"t"+}9i8V0QDAZ\R~КIa0WHCZ~#"-'|PQI qat}, q Fհr52wf ?(eZNp x`XTݼ-GVv_jz(snQ. (\c]M1of'bs<^4' $N"5 lBZa'&?J-RQcE39TKu'C$z̆„)/(''KJLK5BԂ_t̬*|0SV`J:HKm;L?bf!KQqRCW*^66M* 4,SIdjBg PEy+ђ}+bcwŵIwLQk)Q{<C꼠ZPχWW@ Zi/r"_ ^=F>u ts&IҭDkV> Ѡp]I,NtgnŒaP!P9x`:ܧӷܰ3x(Bcx>Fw݁3xg Ct }Hg{Lcʢ4^l4b4մ4,̋*a]زWr9B 4 ܸRΰ jKKY0#o0ϱ&pWx*BTWP<3 z8VpojWs8Wi4){]nrMEl,w?.ygb%b'5uwnĐ:a-? `bTUb/T d' I Wy2@mFA}\G,1E`I3߻BoWiSKU^ZߺSk.s8NL*仃v2t< JIYƒE5^˙b)d137xj(ZÇN9f5GkXל `IspO^7DZ&<&S2i(}])1BrCws8bء E^(0L( kQe&{伯Uo'av:8{Q+VD"pGT[ TM#P)W *D49J _T>ZwqJ?^8y̗4&U G^Df bjRMULoN 'sq_f.@xq7RAW^:!)dRShJz9 ]9``)n(-d5v$PhQxYpp? R ߖ<i! !QɣĢL ^G3)0pEP .>uԓ̇Ѷf&(%he5O-ؠYX3M#kLx9mm汋r\*c5Ѓ7 CX#|KN[0as-v=~v(Fٔ0hh]>t$X_[cɚdrJT[Aou0^t,jHftz:7q}p8-}(* =uYޞr)nDOcU!QSvq!ibAM'T$a i K~E2K󼈞SګA1WQi0 s4#9#JkqFʴ(;``ffYݙ;u7*k˦V_js@Q >k1 5$EO2aZ`: xbMnB .iD/E+I4z[=-?hN~EL֟ ~k C|n9iտQ eI{a[4eRY >6S }@` qu։&e)LbE=þ~|JX2#X"l6IR0x\^Rl@O7,{ؓmEjW.SMg.|s&҈[/KBŊu]@^u)Eo1ex*C8411F\2_% z=M0圿ͮ3=j_obm`; _4Fց`OA4DQ2ժ>-0[؋d+?5sd"A+k8e֯Q9g ̠ \eK4\]6 k^-&5WUkgl50@X8x bn(Q={ iS *Mn=|qM*z]|9=sh.S&piq&!zdqCkҠ'P8!)/Nq^O>*par^߷=^-12|b̓"GDBaN~D"Ȓ?Xga!oqo^UaRl〇"0f10QBJ6h&Nj܂FJZ˥TM-k5HO2ϳU J-A;-= {*η7 0v/ 94 EJLwһJab'^T8$zodW9H\ȋϏvo٥6#M,aVgZѯ1f#9ub-I] I2zH=b"aʥ!W8 ֛Yk,">!omuDZ[ dJfMqv2N,e*ԄWzi _p1)/3+p˰!S3-e3l_Q6DNŰjb^]k+`=F2ĸibk-gKxnLq|j|4CΨꁙl<;{뭻$G doیS.%-%g2΁q+0kL|8UhY._G<5kV2oM@?]Ae׎-+gb{h&.wud;'S,6чYF'Bشhْ"`YM봗HzF wXn;ФT5FYF` d?t J&/5scϠP+)$XMHkU?@Nkl]_^:)˻s+·~/9-Jrt#f;w>bmlPWDi9z*S@ƳqmU \lsNM?J!9Hu>W{C^v`7>]IvI34}nut"F>3[+5UEJqmi;@s ].tf A8s6on:PqE~HXv# 7 FF7IS%2?K 0d()$ .J5(aM]aA:>/*{U8[@i^->lЮOI,lV~IŅdq^CW%G]N") 64ý4z@OϩR_5kYMs<@3v2Ԧ;olE"Awq܇d_[:IR.zWU_t WZ R>N_WH߷ݏ"M|78w&ك-ʚڲ: 7ق^iz5Zh؋O%J92EUJ,Zc]^T/ 2 EbEP4ɦ2UyhpqB_=/Fa̕1wUx-U̫T,L7t\FI̮dm Cp#/np =S>snF F"кSҜ!d1iw-C9: u'rDrdfj쿔 JŤ*y=lϷ_+3~x#G_T{lh#G|/)°8~)y*B(%bPPIȀ8+:x ѻ\?+]kb&Y *B$_776PDb@|7|P}~DEqRh~m' WRZfa`!4bk`H_zāTf0I$GeܘV1U>Z]OтG^)/0iE {y/N lI)C! )ք.2< Oܩ襶Nsp\)&7e 띙ݿMW>$zǔإGPIQt'ʅ\N<:+y_.V; 'U~@4 '^{)ѯjVR[%Q&mWn::V"ZC1VS^;&[835^Zl^> "?g5*䱡nbY=K?TAyjᎃ?,/|»l8SḰ/^hZRULHs;40U'c2,NJVa֭h6 "ɭSϙQ=ht`b.un)gO Є2d"53PM; *UTq?GՎ(U^iY`T%?BUL׻ @UD|{ٵ+Ӌ7\U h]dn0UK4н~HQzG9 s瓻ao@W){ o~1 twHnJU> }"2hme:ǩaڸ^qh8~ `B$!x)D c o%2Jg$&ɚɾҽܒ`PA#2(5GIW9(Ѵۯ_&*lH,u<K>k.?+4l_q]0x  vRw`٤9S2. .*xWmաn,#pp р~5Q(d( !>Wa_#upd)Еy^IxΈ&1c) "߉QCT$bzu4EScJk'ZFZfrZD\ܽk_ 55wˋR;F$!18XG֊sFn XrC#ۀsŌRF"jTHKf׋%' z(I%`R\(SO<>PU˨X/N~-v E/?lcNM=0Ą~ <ϱԟed f_%u) >QY>ZwȭkZiGMOګ.%"C:ј/AKz2|>U =h\e#1' l94׶N&zA 9d)ci$ҷ^623)‡5jPY_JW$ @rwzس]Yw֫7ʨC]ƙ۬~סTP/=\bNW-Υ粴qEuEd%Z thoc1QIlPOc.-6/=ճjMu]hD"6d̎/jk7?CXn8k)P38TēL VJƯUE{'Zss5y{>5W]qD]A&:~ĚorK ?}X 3+ .9Eka.Y%Gui^brM$AͩxR94;nȥ1L PgҤ;I1Ϊ"?[86Hj%1K]Iet nf:֚ V+Q5,I.]5+~ V*᥊ ȵ[T/}(Ƈ1ZG05@[ e f$xniTHMȻټ '_N` s_F>\f~Uv3(-18qH~] ad_C3l=3ZE\N+&?Ե7zɪD?3ѿAQ#MM,(5k `dJecY~)XX$nZY6 vV32dThuD?rYm'/E:/qs)s>;7~p̣Xkx4k0hev9Vqz3;vF@-쨰$ڹ?8Ex;?8J=. ?W.B+!ߪKGinԆi|!z..8PtB}ݎ8S*]N) 4DwrȥY:, ^-rY/{ߴvlCO¿=tw8*k'E XS$QDvvɉYb0T`Opl{* F! u/EDwd@g@?SVooO ']Oɿ 댉250/PFNb]↦ZWL-fYUng! _-*1g(t="G/lk- Sb2IKZ*WE=*2ҝerN1\: <$/9/;d8,lep'&al TPvr636>ܞx)LX )!p2,'#_uo4K?|`ѥiJ}25jBa9hg@MGp cHUX|IhbR+4J%LdCRPj$9mֆ@sl݇1zs/YZcDNܘ$Ԩ`!&m-X}),.gNe$=v8<(61i1]LowG|q}OB~'|s*pEX^cn 0M@||g<ČqV[n)gd )Lڻ)np$s{ׂݶa;|/!ʠq `/)(\kāטg藾ffh${e3◡w21X^t|@!$?p-נ]iWG#P8At k&# aiHmd0/*kH02MGR#fDDS$ni.~V>F:H .5*9|eIԧ,q=xC5 Gf NPa|Vt!1JWi/I¬ 1U PB>ݾzg鄋eD֩XRiLˠ9#iRz? E\$/y𜴣s) h}E.DPmk\u?ah]R0 m.F(X0L6Rtxݔj+B*TMLED pOSiM7nܔDoO6M b*iJz$! DB#Z č{40SPz:A=Q7/߹A5[+AIZ,a٪wo,-4ɢ*oVjɬ8F߼g4'z>ۗM|}X '5**zB©^W=@QN(:qދ)8Q^zG@4mP_dVC/PA2Zioy(ʌQ4?d| z\|S1jP-Wp+Қz҅I!(N'eZ tA ӝX )-$7?nOҟb<}j5vPbǼ67(-ʘtyuJ 5]︢3J NW OA!v$K5QtҪ%fgaRM_pS _Z7f(JNpf/|MH?!Ã3]RuB9ࠃ7P3dr6>g[ڔ}֣'O]ѼBnu6ājUZ޽lS%obt{x lHgQBNgs4TD^g*X ͥ|QCH:u;dݫC41D 2fV P"`Kkh+GJՀHkͭ7Ăg>/m.yFuD _75,>~H>,5莝;7Y.7DDz9orv9Q{*jo:&uk7Bh|m:n)wOMC*f4z:DNv jrir~w!m@!\1TKi+=i xzts+kkRZNKdOUoZ>xZj'0WIB Rfyb©id^s ;vI]G%6NcbjT W> s/Z-P;2 Ԕ|m[aPPA#Vs ã1ky-jišYL{~]| OBֈ*[2a)3ʁb9瓸kIl0sx -{=S.{PGV\Xx7u:֖HN8 ʝ_G h %*)ZF_p6ݙrRWt"P3S;4 %GJrq>KL3=@AdYǫQSH×ۈ,LO(l!1rHd9#tfs Sty|Hh  2O!(BFo :O@$tKe?2}g-n8hknL)S4xW!zq&SC;,=3we/J 0MqJ&XB&UQjTX_f5wK?- T"sZgmV cE+v솏D9[f(JouColh zt﨧v`|.vG]8KB&P3G۳^R[Gtn20RLjlܫYDtvoI$S A@GԈJiXrHӤ}xS5 >KTz7)MvF?BTkQ2UgJHpb!|W~- bK*h4Bj$9c/rWy,> 1Zn%TB[oۼ3詩f3g+;8?z܏tfUsY|X D*ܕ[Q<.5~ЍxzYz] E/OxҐI@%}m:ILr Ulegxt-돃XN;řmpz8Pڃ9_͢Mh7 Y{XHc뷗fw|@ E6ӎw.6Ǯ )rg eR[fv" p}*n]o/d:+ޓ6\@ JLl+3r&RquZ86́x^?kC1+ّR r\u; ].=7iO\'XcudtWrQV`"[IU< ;>${%[T8l%ODe*?:5S9":f77;2U6ۤhS0f9n[Wܩ,;<[h{af͂VĭduC+5PUvOz ڤ`hD1pV :n=8knx9P?:ʿH}aRR;[ ƴ_@@ܲ8(z`4X07at*"(5>jek1 `/P:f׶(Qs hof1m|:KQN<>NЋfԒ1N1`c-J>J+vѳueZ^Wp'483̬+QXXJPYԣ+MM<9=^zO.I㎾ f_cH\$i}ӹBtK;XW1%Rz6"J])\z nh?5>!J%Saj0{n^"Y=n2߅vր,&ض } B ׸mUyHyJ̰WWȹz&/1\A؈6!0sJVRD/'x HU+^c#Ш 3;" $p^!i>PfoYb!J.JGG⡟y#>:W35Q߅(oсC)^R!b g4_e%DrTM!( #L54rݏAKTg*0c-X:$z+zl)ంC#QAzߒH"2(uo< ^945S^_~)P5y ?Y[oqdMJRf_Å,HqgݠX_XeѐdBu}ތr 4g v.ukGuBo Ά>qY؄"߆d*BM6C6U[f{FB?}5!P9ƛ)zoG6l KeZ y-)ye+)*&-ٺi- e|GAߓr21 K(r"iĿK6o']}0 ŻRhmx.-F{J3 E_G*O[e)7_k.Ta~>\K15Ts[`RR"bn4ܧ@75~eGF aw:9 *nuQ2p!+{"2"[SxEthgq&_܄HCkuf0+7Anm%@qtjmlJS&T[ENLǖo=RaVyvNfa$# M/Kܭ VE!uhKص/6;L_X>F/ eT/C{Oq>Nx"71O,PE5b%.xyjOha0>_B*xҁTTw7;Q@gʓJ(;= ӌ? gXT^J'z s$gk ʳȯ0p9c>jU3[aSs&JX a5?ȱ4&YxȊ$ԈM K&Xa%L(6A/Q%u!.F \HVm1$ϣ:nsrnSS#Svs.8S+;4ϝƒ ;9o>Qf@ YEKOq`C-.Ĝ,ͷ Xtkc:j .R"_w"FsDƸaیh.?mW Gɜ9ݝj M\׶0ZRPGuߝ? &? ES:ӔT^<͆ /ǮƷ̰Ў󸘊MN+L|͓(xUz% 8Z..cM7UjOs:D)-c>|M#vƛ晕) zd^Rb_$D:ꀒK(ǯTo(˒iAA9CsR`8<#& U5 iwޟ)ET #d(╲O5An+;oji|"W\ϛz 5c"xu@ W7)+0X"~^b8~c٨}ZZ$= E}+!9S_ HaWS?ڪԔblƂ]6a)"gU'$Րx{7 )$.MUglO7Pd`sY\BhosyJ >Oe9u\ؘ@їBmCŇ);֚?f}+1Nޓ9 AF.ѡuG 4D)\QVC)]}ޭ_]zϗjP-gTu}Үև^-;Ipx8"úD|nn4>Ov#D}V<+iH\˥6+8w(;".iv]lşmf۔(M ,JS?Hd (o 9sZ)a`2›$e9[";hLl=wM|kpٴì&Nm%e؈&v k_g(iF0Bd G7gpj2$$ґFmhxwh͸I&7[+:hq9j(|,G|QQYr@0TqM${ bvVwW{e/],Qn" mϝK k;c e8Tޭ`|0\b;4J7OEyއgG{bz8ɓX`֊,kqȬL?Iҷ6܂O/[GڌA;*`&_ gf+O?hOJ8)B/JK~okiלeCnu!!S [[З w'"ȋUl⍽OehWN46AW:HG7$}9EπlTDy8ZߣG7CȘ{?CCW:]ſ\?K[f,#wߦXs#a_P],2kyA[CFj82_9 Rz ,.%3"xzo@G09t;)_(>7iߓ"acsY<.ߨu=wJm;uQŜ6Jev?*|FWFe'U{I5mt1M'"OY{34ˆ8B5)xQco*7fyIx1;"J Ni^‡ *\̽RJt]>xŝ}SRV/,}@upNħ9'}ZZ$= E}+!9S_ HaWS?ڪԔblƂ]6a i$(8%pkV0ǦҮN!F2Ď}\ _41cg"d] kPn5/7 Q^)j9t> Tξ`` xg5&*b೭" 푍9h*<]7KJg~W1$RY]`w TIq`?,<>vnq$H֜΍Bo6ɰ͡j@aR3p1 C5V31:w[8rGx i$E=j:8}4dl^x{I]8א@^gJ/UQ pD}m-2MF"8^˺ AHg/U˚8SmX5GS6U0q%w*q+n؄ltXEUt8L$0Qr=[T=/(<*/[t8oFr5xsgL4K{J ٶ;H-Nz|xRkIADF- N3 ؒ{&! K2GZ=ۑ&ZPaT0$Ϋ؋ `Nfx/:,y9: l\M'0Kw7T7SHo=ԭƋr U3|i0\b;4J7OPQ7"8?"+]M aN.'{A60G8B` IQ' *otUEz eoml*RlZ?{@ Pݵ( ,f/nd"d,a#w U(v}"# 'jU$r?tف-jmBS.؂:9q09kX}es|ϯj~UeߞߞcVҳB;-SiX`$ aNkSkn)мghSQ`EO2%!ZgFK}k#ӨU  VTŪ3%&p>hVBr|EuF0ICD֪zr߫eg82$VE<ʕcRёP5,6Y6'6LyA`w ;RG0TZAMa/j,UHέשM_T9V\]OFdOl+)<|O:n*x'f?srس?cns6`w=4W[iI{Qz$anC`@HSTUŖ$o׼^(SfN6LRrR׿+@;s*W|:n Ӯ#H-χ0`'vܱ90\fu7E 7q; % $Y@̐l4q¶A]@Lev5Ŭq{s-CraA9}zxl~X/*v֔j|Nfs#Fyv罯NrM0#[-[:.S_iN|80KX`ӱ%ӉQSo, t6;|EW=#tsw{' wDtk 4xX'&(bJHP3Ӈxů^C>jMvX"Rd04 rKϰ8_>lxx?\.=6?Ə%}]5`;%" =rAȥnC5@veo$W=Px8+Q|>k:b-y}B2?Z᤼X8|ϒ ÓZ3g\s&u(sp9H{#['/H 5uP") =}BdJ'!i *;l]V[ #R<8 TR`ʎ!ܙyHE$TYvpeJX<hRM\GvX;e;UJSuVU={Qۑ"@Bb=c ]\R$୪ǴP9=qjׇBJDX -WIf}tED@ Cbo)˛ /hs6'J[5yܕ)JH1 4Bp>gɿسȓ7K\CQ~ʱ(/\K/Ik.Uz+{c8΋G 8f Z 'wl#\:KfN[x2;Qo)lLu,FC\z~4>" Epն7 $Kv,"0߰Nƚ}M=YY*V%!VG"YCX#"84lN&ښS8:Kl 0y4=-,w5Bek81cgJ]gQ7ügfW\ntbBqz1JhE$ &ʽXW6V@.4 (nJ-;sv !jw(ư޹-7372qµyaq|VE"W7Fmb{ʑ_3GAEuEq,Ћ8?:RNw[HkH vUjdH=VI4" lGiϘ*r~.m(-^h|K c2쫮sFsHV$ EۭMcj`&5d&/H_>Ţǁ)`*K-o91;T:lw$Ԇpr诃 ^8*j6.|IIF6!"85zŋx )x11U@Sė2 Qe-ϒ#Cëdi@{qhvr Y^Ϗ륵Z:,%kjDB#WV@6ip"*ɩNKc >զcѤbs 7TJY)c(q8:5k&K]x+|,רhU1+Kʴ~$EMzvᬞp3m=Y5?.+m7MU52pI*kYtBjI 20ρE ܺ{A&HWDgOsa`zѮ tLvhQR}C.V`e*AMؽyF8z^F95sy'5pkR",tgSrعYU0Q-mE~iLe+bJ nv<YJ{aNk]E@l;x6'&zd(gp">>'5֋juo&^`oǁpf40U,=pƈAWC\}y?ʤ@hڕ W>1u.'86$rʍW a*Rfʪp)=tc~\Un #iFotOJ~h m\džQ#?W@EaF~3'u]os$#芩(/ $VGzS9}IaMw*C%jSRB0e91sJ˽[=}1q+-jYp U.*+a6e D~zZ=s @o@ >ssZ޻h˖pj2VL{G\l6v.8YMO1FUCv(Pf5~=ݞcxUGI"ֿNUȵ, WCզc$YbX'lZ5|x =e@'O*LKhH>5 z1=^޲Z ? Gf܌89-+,@3jy]A@ ({>nf4~+\? bn/+!ǵK!J[%Ry/)nB#lc -f;|%!jv&gKɬ̷Ū^#m\,\+k1p&.dh%.I܂Њ˵)JYQ׹-nqZEe7x=Y'W^lJJTT/rog#]*xRVoML&F MϕMa5ͺߪN J{0[^[vsVZNݙQ6+ 0 h jRG!@B?Nx2*LZqg4B]BZPvR!{߿&)Rk PQ|V`dLj;ghvdf> ކ^?\H>UX+ȁMD?VM=GV 3qľ[85۶T6^^π//{څK)s>i3m='_aHT\մKW'чH@b/2]/@#d&Eqt^Td&?eiԑd7W,}C"- QvnaHyOJcCW>FTeaލd LJy+$G_r8ωǰ:FIK(E3}" ^(e.wT˹q27VpQ,_ߓyt:޼S6t -<ʆ}Hs߅o yAoHŗGk]mb~@lCPD2 3>ĝMMۋ$W]NӋgftrl{/N#m=[g6H3#_tpT%2m2BRjikI/%q|} aȢ,MBogrBSaU)(h>0f#?Ш3LfvI(AqNv$ב :'Ov)w(a;▦3MCD釲u3>eRux]Ch\dKA'cn5p"Y?_|XF03Sl20{n(j;oqE:$gP .xY`)gt21mSz6hCQK t;ʤů&7۝1Fyh}BJ҃ρv&q'f=En E870#0w!-|x3St /٘O )\o&bOZ! V>UOs'V0لYhg3SKT&}6fK'$XMU|Q*xא1q 6xQG~"OgG}I訂/&k͘ኇá׉R̩z#oŊ/+Vp YR# $ڗk%J-6]H,ʂ}HO)KI]Տ/>LqAS\\o@-UNsIرм:|h,|aPl@\3E%rx+ƕl=yw7-A:sA<!"RsNjzs5MYhl,{Q=Ѝg 7͏z\.FZ_s0:TC }$cC@lsYweGxqSVHȣ$(WCg O#V计j:H+cv&^Cf FuU"~t;|nG,PL" НQ~r̀sJ QDGUXo, ¦*$yG\~V5 Su樵(D?*ҩ-GǸctm!^( HZZCLu짥$|#{E=_݋E {%M{{YBmGyK8_c𨼍 rs4|/ /,~"j'hUIRzjq ;_VBW"OsDnI:ٺOu^06[ImE1-D!f)?4\^$)S*"pzA8vGFt}ߢS憎"!x8="62Dn*$û͟xz]9_G1^Ϥr 2\쫮ˌ`dk񩋁TvTmmS@N`V0.U^U?m_UGsh6E])t[<8M)Z_({O5{yO%:P%o6)3*j)\f''q˺;OϮ?w7XfFnvӫ;wE댘D<Z'hL(_ijr3 1t]uGbdrE \ՃD&d/#Fkq5ͳD78nMMۋH8i baϨxJtk,E/]d.vmߢqW19bZ#i7֭4w-8+v)5ƵyCt0p6ta^z vn)EM(XtJE}*ȱ8 ;Ҙ8 0ˎ% 7G [1aRm'"鄑v0yӏ_Y{IK z tN;f%d×kGy=ϐ}Jxx &dBӎ(qIC\< tQxw$"$7z -AF70 nEhTH@:4(V͵U%ϲdb%ld> *ϫC~zoFt@+a .~!4r% Rm 0y(<Y'mh|"v?3bt\K:QФtR[2 B*~N8/(A/%iNj0Vgu|9!a=C@l.I@,X;4)fLIԎh*5XnXiK:d=}fU6)d!aлUF)Ì(m5PM@sE?7O}uSm[j`sohPԸXݤf_r Q4xG9?ܴWg3;.y#yK fih[' 9,JvKqgvUQۛz2+X> 3|1<$Z`Q<'_^cSL*dlXC0m+W}RКSz\`+e'YV UšFc9`c>$ʴҮz&D啛vM+ô!/`z4EBe(٨"nb5 n z2d0 ,^A~ʍHyمKܶ<|'-$vÉ=Jw[ybr8Lf ԵwY+j[YG{Nldbq i?4(MK7L?E{qޘ˞ŧ&&b ao \7m$5>{e$HڹT}P]whgP%2bٴA@v:A9 4w?O qlV~fPk7mm g߲QZc:9DvY" {# Ӝtiq:@c#AgB'o/yx#ZjO3<![G:{,xk>c n2f^%o<:^YQWs%vs&E]sfd&HV+;mMFӻ&c0ZT9j<O ߺVpvVw(&8ƴD;F{dQ3dwˏF 5 c^68R(+ֱn-a3ԩt;!:C1MD?x?qnTD5Xjmt |RJX֭>r9?I׌c+Itq$EYis86>Q-SWǑۮ(|ô@UZVj{u{ q`67c]jr- -Gz(:Wr%D,*NoI9:ȻP8߫p gjb+BÞQ?6|;@30RL5pw cęd]:&s:W:nTU0K};uP'=݋:xLԨ %i_kFUxL^v,@4ki? :+ڥ?#<1ؗ;G액AFLg^%β{w9OsvK#Œ;G*6[,gȞJtERl-.MZy6J{FpB )2M7"%rʯoVI fhesHPTo͕s HL/ׅ@\kd`L-pcN? y;5=Fྡe2 zh(?Pgq!KI[%;C Vqd=_8xrγH֬7j GWbm+YvҪ?K01 Lӭ [a&I"Qj"f+mg-R@hJނgR drl91 }CQf.\Iы"Vϊ'\^.D(l53`Rq۰"eUk$AK*Lwoudi0BO WeKl<}niJk*a%SiyO[N:W3V.C(n" X5RUrjrҁ7V3v:VrŀnUhסebD>^0Lcy.vw(`LɯOeJ}Ii.zq|VE!a"Sovz܀<,8<(a `+734F+&?!E̲R:qD+D&U_AR[ZD‡A:VIv>#u!/~rV眲>nU?29s. ?쫮sFsHV$ EۭMcj`&5d&/H_>Ţǁ)`*K-o91;T:lw$Ԇpr诀]eM?O_dV6Z [gA:ƴ ).NofE IV2$/? AMmn,\LYGh=8͢7GZ7#׎^Hw^+eX8e(g)2JIi~!7`|%rX+bhN~jYBu2*Ԧ%7 dX.{E~`JJ@n; zSkBOD@:DT׮z&hJlLHQ|I~[/|&5Zo6-9 D>C)IǰBsjɮk󓩓b@<̝#Ȝi}c# |n#fL*_|ɶGDl|w041):pG|zw]TFgv,X,ϔ0nK1=OI]NZ}UN>1ЯH&V mX'd--4~JkK-`^O351 DĴؾVnw(ܜ/gj4o‡Ğ^nCb1_G#k3MЀ"-ucv]vy,f"iMI]y˃Rl_*cOWQy[ZIͥ!hBd6y4=$\Wtyl93uUs[Qb6R;*uG3=ÂHYw\B2!T.ܳ.@S$/l9Ẅ<@XEY}k9zca#98@$;- I0UQޔvp&_RX{~N8 QDn tY_w yѸDmw[}iBNW_\fl.+'_ O*!M"k>{1 [drsJunMGkYɬk=sgݖ毛*h`b9L-K ]a`pTtFڃH&Mjw=~@\)S!qa0wbX[H9Y?s/Y}®bc#;؟#>}i&\itt9||sQ'#׷-iV::;}gf1IUrʹr<Csg{Q꿰AWTW~`T/Ǐ}]gδukN.8 24$J:ͬu,' X>G<^a FRV *k|YԬb$Ȍ=Ѝ?;$)Xhh( 9"q%iNsqo?nl2fVRʣ(n4O4T5nn]EWq|@ɺE7z8xtz Go(^c2_'Er (n^g۸irnUܲ.rSQzvҏ6$(&*=𧼵08WNgr?g]jm 4Q3|S ru IeyM߭Z6qKIQ\\<kML c 8UfBɂtw![<95Vc#hDr=A 9f$DsqY~FܩX[[=> ;~ksމU )f'%Pys>N|Qn޻8P0Sh ҿGMj }5C)xEu3YI W]t-6NI!bի1Fo>G:&[Bu! `?`dij_{rij*hR߁?NaufhbD'9D6q@ O^l ;\UowJ˞aT^: Z' nRD,YFe{cPTϳۂnor fwN=TKA^J=U(xl(o'U՗a_!ߎ.9/Ibf* 6z?t~(9nη$Q* ͖)|)B xihr>쟥/I(tȭ-)"1\_]`,ER_cWhO6?D;~+H98qn lU ͡MC\zBֱg.P2hoF0;vjˡz+Q vm}K;ni HhZHzD+m>LAUQ&ߢrOD`Mm[]qW*2e*.YVq soq|4rh +%,h3Eűn+QG1`3[%du#ua;B@Zr)~j JDX'[%(w66mb1Q^/+A׆Ѵ]Y9 `6tv Hw)qTȑQsf5 #|~RbMRmm dMjNGY7I{QV<{Fm/!c MO42>]Q׎wt;Z52 8fgMf|AY5YR3C JBx0uXy7D*!Iw_f=1(-6дlAJ'~ʒn*13YGG?R8Ћ##_hv{a }@ECeLK ىNv?~our+˯wV?l$f l'VSuVg\{*MxvX,:the e8p7Կx LԸrPHa1@nbl%51O;jl&M)w;qA8/=SyWLp گp赟$ٷT"p(Pi =Q#7Ċz0bO1h"µԵ+Lع6N cmI ҥ7"֜#Tw40Wglvi&GF*lFn=-?b*]!j 3$4eLãŁ ܠD,;_ܯ&dx[ Ο:.*XhjCwدmtl~7ΚnGM,KMuC ʀc[z>]@y}`߶ԅmY9' wІif +_⿜$o̚GJ3@3 )kblZ:HY+/fTW"P_H՟ [YW;/70}4yѬj8<9xo;eղ><]p>2J9pq*ȉtÇn3c+ 膹NE6*yasMe¢Ľx_W="4Zyj: 4,/ ("'t/0ɏLڐ{1eA0KXs'otZP cIaD~K [hLuAJ#˽zĞ|c^SչM|fչw~8`INL(JU<ʴ@fuLTg~&@(>'b< ##q 6PN&d)>fd p \]Γ}юO?1kDz{Y;/0$C4#cegBO?c5y.6N∥AB>q!83 o1 c[ww*Yt <[,۽wu9a_Ka:d9ThELv&Ѯs>a(5W~ <O3E'FˋYm@:rcbRA[BypοTw]KBi]lJmЄd7 Zvm%<%n}/':{-OT6\.XsG|s.\ :Կh&"] Կ= wH[# >9g E|J.&\3I(zHٜD?e0Ʃj^Ԗ Ng)=F/LYIIar4Fg5?RǠ r+8hĿ_"Ovs~0F֗%TDwP4qЩCp$%}c+t ?ҕ769~o^ @~EmicIjNo⅝h\0g@~A&:'$oSF-s![lzL/DqȧCEAEzR-Q}ERL}!ԦB/ Wǜt-6?^|Ul,gX&Ұ1mϬY[1A)DSZ3e悂bg4[FõQM0!i=@6vO@Ҳ{;HV~ >kޅ,e8?&6JAJ5 D'9ҼWpv't/%muog(x&RR!n[m5S>kO:} *JOr|C<։c3p 5fge$y%,PEL1aR;Xb YQ~uqBiPXp[z5XJIMi 2ƁT P+Q(|:iþZ2k F=RQG&js"j?,GUжJ m_% u lcٙ־-3LL9,TB1Z%r=94Oϼ+C|5b3LJ*ZP #:NsOEsQa_MDXa&O# ҴSL-q2<\Lp_YBr)uW2K7Ȕx:5(?TB0W1:/WKg|ns!mYË#~=W4oձtOo@#T]};Ǔ]nxWI n{蝎 q(^C#"M(%*Ww?&T"!wZ?'h(CNf|fVPT*V~T!(b[#$P"4fo9=VAvgoyݡ\cg.`cPO̺L">`a/E hz\R[ߤj3 TTzr ?m Ak5ZD9eYCPu /)pŏAS 'lTL0[*l>ftZ\*~֕Xd[C5m= aBZ_&I/§l)ZqR tޔEb'a]yj0ILQK0}߁RYJ]`"V+^;/n(,, =ZhA;@M3`/[=q$W`QL%TNH um됉 zW #9a6 0[S8CQHْ )yq}]<C{o&^FD{_t:ϩ W I.Kw!Fs)f!y3B5O ,[)~h3-S `DID ό4l}]. ٝq=jvaƼ=fQm]XMPW;GQ6x'hʣq˹!'|k՜azck~LYd1;BrF ] #lmYJQG\4}#>lpcjⅺQ yIm J]$ĕrDܼk}]K1ZФUvFȶ+fOwn@ q>20+zlm `?ސL!êJRC;HFw2~?,M@'u"ȏs $hC }fʉYC` 7 '9iD( s$G nTav,qh5wkˡy͙;'3.-ԗ,ʓ )vFfX Kn,YJpjv]v +ƒMӂ-"Xt^gBGJ4t#UI>o0YgonHL osсô.*"ili2'z+)y`rB&z: a my.ݶ׽&KBPnmrϿ Z>}N)|회.{1 osC5f(ة)qXj1и'*'#Q0]nʍߥ485Z՜CexԶzwܔ(lXcf:͕D,ug牉aBN}ݱ=}k^˲Y4jmZ3i3Ë@ŒWaUdžM%09zI ͸mD$%'=GXPUZf8I4,J!#CGoL,A;0j"[>}M#֞YEq|*Ĺq k{z^e>( RX Wh3"UېVJw;vSsDvE&Tܱ\6/=l0g !8-o$M -m g~I"W֣>tq{9ClAewFYN՞9`N\o)D:GZш](/s *FzV4ì ezt"R+8 .@ JcE 1@7f3 q{&¿F7TWeb F*Z#SOs^kQ  Zn-іrSmLx/Qψ︡&`hS2wR!oT=ZTapFppxmn4]h-e7=X(iNMpuI{H&mLJ"7L+< [k /`IR'/,dR03nSj!Q.4xG? '79Iۚ\ĭSG47lo3V uq:%HNG ɷ[=Je\Ħ p|kfuڎ AU<;Y~y=,e3|(Rwݾ2@GS,!Ϋk;#/$otpfރcR30? RHq=BJqtVk0LلQOօ4S$I]|JݩUf\#M68 LBRM$j/oZSBW<m j#ԜEgU}u#{-QJXĐwn2Mс1 ״K]!%Tv2l_ ㍘&4P O^ƇN|LWXG-<uR^QȼCEL;~j(lX6ZM!-?ii .` +wn Jv˅h``uVЇS7|fF"@F,DZ&; b#~n#}ҁ8'LNN!C=e*a)::0îR>a"t5 /j29;LfMҽԕ,W6#4Zt?E?Z\ko6 Jlz@xҠS<:p~rh瞯\ {Z`h hZȕ#EQOrn) kaXڸ_LG+h=.>Yx0(,r9/.#THݪc:nSW1a0vq .Aҫ\pt.22"R{)afNA<S ׬0׃g g ?p5pW]k.Vg{hZ-+  +0H"bkqiGvJp O3#6^R'Jm䃐1 kbo ]6) {)`yN3=o5 ŏM?5g#}vᒉZ:QUи MmZ䶰۲Taw>1046H{b lCnDh;J`is)Ys;̊_&NܩىЂGSK!ISc55B iaf:8EVn2K(9g(~LV$2a". wa$٪ʄ_'س֮/enb0X1jC#&Ffcc1A9;p(>C3?YW nϡmUz^9V ±չn[u Gy[gZnN kTӽkZ[ʪxv:25kD[. ڢ倳EŻ/BɨzJX#pm3N%شUR 8SMBp;baAG!)Ma%WN*SƲO?EҵB~h7:zte75ԩPB"+!^ X.&dYT<.XCĜU'4H$Z1ƴZn4X) ay4}wvi}8a6 *BO݃HVG.GS-W5C ګ/Hn:}LeGLBmGwTzJK\|~GԙMLr.n~Hl_yUʎ/q{'٣Ƅs33Bvwcjr{{Sl-Cd?T‚Juͷ_WvNԨ0ص_a<[sEp{}kdsb h$M|mSQqt%pw3tgp2/b)wqL%X,g}uR-b\ihuKl9[p~*KPz=9 k+MVK|8`IN7u0ڔTi_((.kѬΆ`4j3L!s*GoŽ4F`pZFf6DpΞd<Ol_t$B\4#OTD“uaOE]QZx/g:̐=:՞/|gI.Q 6RuȎ$rOeMvz6f]šk sR 3SQh}z2N{k(i?-F椧V8)/L 5$YMoo>&F^gMc&G "J⛸9R8㪆AaK⢆DOaZnٍujM\ nz}>'zS ]lHIJT[ʭ$( `NKDSiv::ZFWW۽䰙,0Kg{G,vײSK% a4@ù̽4Ul;%ʰvH, 9+xPBV5GYk- pfNClVO̠RKj,(:}cALdM8أSfٽInxbHv /f ЪmUadhtB|rf>bOwϹFPorٱJM!,D:MJ ]2{;\qT,XˌxWѮ+?0wgohBw@ߧ4 ]X:⬻cH pQ!x0*t@}ҒRGPa{5'M^Xn&W[3kJT5ky%JecA0V7zAeaXH5QKĆ ^NK'&(!첗9x{%WJ̃ߒ:vLÿ3&Hθ Fx v*X%@<,TϭN4 X]#+OQL&߈%ָdK']n{%Kמ .UfSWE)?k+;H0ҩ "8kf=d<n܀d_iMږp,$?Y^ս3̥Q \a3pAL+¤垐ך>J&dnq')*P@3_ c8ͱ'٘Z %7S Q%A9: ;䉑v;d});HӸvMLpV e1Jߎ|xZj,~#ku?Mp52wL+UX&{iBXgL!=$>ƽ0)"II,Ue^#z OUMMmt>ُ1{0XtddΕS*:U[TO[ 9 k/b-Ԇ #|KL b*PgGye$8-յ{<.m^]:lbBTC a&|Ma}:DEUIqE,݅AOJSLFq#} Y]O!?D{S%j%4G3`쉘\Z: SZv\7KUβCmw$~񳏙QƎRmkn4:@ueěB$x]5- ⑧o͈UCy\k' HrH.n |:ɗj<ć>R%Zkn3KխzX{ߒV#7͑ڛ*]4EI'R Oڠf{U:$%:`%v+g5S0@ :>";nLqzL/2<4PUA5Vs9Ў[, Q.IJ-kA(^fdIaea+ _3~( !z<(Ak13-j\gFfu=2A6pU\C9VY6,yuXuVJ3ngx3&,@QP=վ,7hD\;1H([f¾Lvkc#R*rLuе o?M/ߎeY 3j%-Ur,Bsw.;d|vE>ەĥfpNȱg}D yRseUD<ϱW鮔!"m݁aS0_֒-EQyd"(D^UN2." 0/o pnˌx]@e.$X<~TIsFѨ@E8bKQ=]C\!PM, K/1 vF߲,1mh6`њ#eOs$oyaG߹!R'=3al9%y>Aa{(k7g4, 櫜R! 5k{OIq'-\GjGnlԾ/ HLGy4kQ<ɴ"n9BF8q8t<&X{H%Håw 6sf 4׉|ɒ c9MZ"gDF(e^@ 9I 3ce04N@k9J*n@BG(¿pg8L h蒢WGo\ĊڸG'$hM=[ld@j2+3d;ʺZ$& 'G > H B;(2X>F_l?d<>zxpuef{ m~Y% ef_wuR`ۍKETn!GDw?'&A0Sɒbf}r5.us\j#+H88l€ zQA+SrKx/U{mTg]:Su!0'e ݋7FD`C0YG[5JdO]Uz.tT ͻM7x^VtN-*; opPq %#:z^qe`Hg kےv֮bT m0Ո3Cbf>qށRx來zvEK\_\fPv-ID/0 Z}eާb&1j/GI`7ȅ2C jWϼ`vEPA-&݆cȍ 14 26.BLO.WNu0lndF%_)VuDRJ]xԂ_tUQWbc k=Pff!jdәg М$P(_4V BFYF߾;5']zW:.3|s^rCckQv`5L0˜p` ͫ,*dw5)LWhpl"Quz*=ߝ蔔6ڒ¼\Џ꠹4ξ.-PNFP%~~٠(= n La ,3= ]妰aÝX"qPKwѫ=FG& -K \X )gUFDo%]F^pO Eѕ/(*BdgH̟ 9DvX#SE`0vÄwhhTXϐzZM+AHg?ha"昕jT-dGq@[yAh{ܷgIO2vjNJYhTZYb,(U) r"DC?,)T8$9hԓEIeJT,Y9 ҙTk׉EM32m@EgejleݝKf- #_@SQ䫡} _ uKC'(*-8nehR\ev0㢢y(/9֮_@ߤ D9,y3[!y`B0+ ?iHI81D*  xfr/ʹ\@eޠÆ[6볗R0yXזP R)#Myh=0&mY9n& ht_lŮQpGv!\.N-k``aI5hzf4~l(p;t@9"F:CY5bƱ]$f1N2(E˄= Ѣ~ ~@vkX9Z]?33!3IF5I}6MvE@ٷ N.+(mF^plTFƛs_n@޻P. &)9o?\jQӝ+F?%O&b'LKjj=嶬93)Lfga K\=YL3  P{i|_d3>'wtK K+a2I qhBDkROV +z?rf" ӑ]a!f㵄# "҉,hN0$"Ԙʉ+i1j>:b &8"U eM^ `Q#!ٽD#{$~ieT=h:1=V'(MQM}-Pջ)pU^dHx`EWi؃7ePgF _ KAO)J2Ȱ Uڎ `6O$(&w1ޮn|!gFW4Rav㖋&]eٷ|J&DKJ1@83 Ӆ$O uMvHg-rfo=:= շ7)h"<,qD e]ٞ3psw;kJA,pNWe:?#J L]zCV&\N>@.'bh,ֵC5exVBDݝAd"S nڇG 9L\l9U+t)} GuJ^>"bGǓEHEa2;&d[E!#qwBߗ1p_"7!lJ =`[6jY &ۏ<̨njt쭸EF_JE' @-?IpzeZQ"e IQTLqsOoʉ{kI؍2}wMr.,ɱVF̉ k]Z jn~O+WPsM,t60ֈ[)ʽT?$rF[c/a`'@HC-UT _Fl*? Z)>A &*VLmtTUWo7 6U[ڊ_7qp2-,q J9{S{ew3JCmrHM4֦n?Ѭ}N,[/ Kd/s5BDq۰ʂVZrw)# a?PLE N qƊ05Y0֠5m˪kܷVU߭f^/-7Q|ۜD޷^C+}.n``CZT&<-晱Ls>o5;z ,Bb[je Ä9 lrKK)3n*// U Y"dK40UVg-uKʝ۝XxGMY 噴$F?J=*qM'P'/> YB*[^v:DzǵlWg&UjHb-Gw iųIBs&V` ޅ/~_GF+\oh ;T_,Τ,lp^ܺ3v mM.=*V#e?VmrJQ С.;U[;hj5V]mK˖{S֑D܃GQ2HsJ=Dg%:)NmEqLJ8[cfLfN׃'wUrr M LR=A@JWpʼzExLq0ݒa*v>jRK:͖Gmy3b姠Iպtb'i6f 6jLI%S-H HCz'űn4UP@i(N>-UO0$Oˣṋ.[)c't yJy w,W:EjN?RXP#U+Gt UI#PF14--?#{60ۓ x^ɶ4ِ jRfW!ZCP5diހ?UZꢝJ'W -Z{Yɧf&!eF" kׯ[hXi ZlY$ݪ2*x/5B9UwG?ZA/[h-Kq47pD]8M?Ozj. MK_;#YJx4Z(fK$lQ}+);]X۶6(~3L65T<`9^H!Y,  ?9&۩jINv_MЉ8J `=[wy1pLRbW5h> qFnښk5[F7j ~!QA# \*i0?S,>h mQzB RE6 4Q:U+*MB 'lG+HmK_XSNh<ߢRX-\: kcylb؂cB2Q]!Y63.mmE |"[B@_lYB rxrLoC3:9y* ĆM g~ڹ)hxpזk uh_³}!k;Zw ܽ|ZZ&<%vꤏ/f^LN}+>AhWpv=͍;9uvNg;R_ӇfBeb7~cS{7?"}|쳋±i;r54kB6-!x&Qx?-t^+4b_j*&ަ~|_ a9NserN{Űb0'^_{YsVas|(dqVdhicn-b.tw=H݅1%|H c,NtX'y|pӰVy#P_cj)WV "7<8ó3( ŷ1^T 6 JfRd*@sq;2v:KMR#phԑzCg-BW5ʶfw5Gˤ")TA5H" D iǡlOkBG+J\!m?62 *Z`T3t5ͤ=S\l}2`rO#?6>I 9kbx¿xg4"lL@e@(?ȫ]'5d<>/vƕv2\lyqT0D).492ctEre|Js?MYeztjFB&W/:ʼnň+4L c'}%Xչf45onl7L'bN^E[V05Ib&瘃YE*t}wpΖAкm"nD_rkpG;}QVߐ' J':#-SLG[_kwId`nuX$Fء"@_Z38A*k?]6h؜vEHwX0Ks+WK0j‘dT/fy{=$ l n[p5F(\L.rل^W!`䍶5iOVtgEj vt7]kn! )_Hr2gUXf`;)S+ˀ*vr "fxϦ,I3U/ \sRSWRKbXz  0|X"i-Rm fj{_E@A3DH/ g3ls S]]$gcOASfۺ_(UXE)P g5Ok&tˈ{fnJՏj}`P{x['%ZSﮏ>Vk[kvr|$g;!3,ğ׋Y!m`C[o@GyqdA1U+`'Z1K"W?pT_99v׌D>P(sR)U=PqɒM Kn+'b< ##q 6PN&d)>fd0 201q}юE5cc{Z|7Uɬ::ls&ӥMg?ۼKkA(p-6u^`k?~aYUm|l_tҏ-i|~5:4F^҅œ"`X1#yмr +)r*bF~Q kB18xpzVvu䙡TSX`JڪU/ ޟ`0yfPk؍K+ռꖳY/aܺ wU7G@oꀮ@Yrd]㭭{r"aÅ]k~Zىe֮#,QtΠRBd wU3t ^DSe%T!,R&wV>{zsߩj-3|!vT`_ʕÆ"Spd>k a8Wqi4SdTǏ@:rx5 O)j@nN*}{ LBZU(ZozdA.AFD;3ΐtJ)?4fΚA$I~NNP0'Y[ET(X\$J\o ZzB9ȰwMݞLo݊V kS ~GxX/xLmۈ4Z70ʖkf`]@k9:ǒ$zU敔W y4NֳsYj?`Ӫ[ڮ '[IdC]*ᜩNlrz-޴ef6W8T?"(ڛ1zDJU~_? Ja=u l01Y{Ǧ}PS=n LG iEOLҘ_2,pqo2;_Z'.c3Ǣ8J-` ]ؖH7d~W{H`Ӈ|"zM7v‹(pevՆNB4O2\"έ݅!':7c%1դ8Xg.G&G1B|p"y5iR##4's76_,(>Pj¬F8d.{qkrYrWi=Hv)f1XiQ a~m/3~x-86Thc6$voRqQj L38d2,FrhK?;?"X1G¡&k "Fܳèl0&=^R *ۆd2=DlLT[bNp$ؽ+D04*y)f2Pv@Ꞝą&En{@v yE%٫qd(իۙyŽWH# +`/ Wǜt-6?^|UnnmF<3NI4 .x/f$2_fUO d[:`hUt/5Bwo=0}Pq(tQwM".@ &#~JN\u*pq~P˵Y·ym p?%ez0SOmXAJ^$Zqlq{>Cwuk)J`1r2Ql $މd"j*f[7xuT nȪub2bdwAk4=4E;` uy3bֳtLur'7(lY%9%TPiJ6n2MabSfz=qK.p}g ^;UyfpYT#"ըojn߈cI3|R,knTpo}O{HZ'>H6 v:r`Urtl;KH|{ Ino5UR'#&ן-ssd)8}zqJ:َZ-?J K,ht|]# 1S0ْ7Q(Rz04 n0!<) 4\fV:c[0UƨkߒQ54DMN:qWAR 4CcS%k'KCH%68lUƆ}@+m>OEsQa_MDXa&O# ҴSਭiH m@а.` 0+v5xR )0HoOqitW<`7܁6L}2( ۡ-?3p(b^b;r?iTJCS]ooG6q<ۑ`. {,oU1brPnMKcԽ#"GVV^f88Y[x̨LӴz)$w2|ڂ3OHkQ܏ Kȫ0].G34lxe]S*9tn-i?ڻ\tX?@y/E3[B 'U"*%ԕgf, ,Ő+OB%>8\v(g=ֲ ¹r8e~C.r48ЏGS!(}^coUDQv8^ؠ5->}Cl͌rE;J`qlQ+^%UϸY+$۩3ZF*iw)#_u6 )n>zϡEY(R ʶBwl*!\@>U2|A}[bAD]??* -̹yPlb ƕlUg @imk!MhtQ:wꕴFuvn Mаbޠ2ڜ)=1e6fx;o QubCq L.E$I.1Ԫ @%Orf0Wi&-niH M.MKg#⢭=D8"?ݨ#uN]%BfER$9"U JnҼ"\.A16x'hʣq˹!'|k՜azck~LYd1;BrF ] #lmYJQG\4}#>lpcjⅺQ yIm %UzzZr6ta&@NMHPc|ޜ?Q焎&(&R2xg7Q4Oy -}ʓ )vFfX K"JDelIq6Z:7MmZ>HMAWms8Xjv2K$ 0QMh}{nxB:IH']?R5o(5YvMHz.7-%@}gE}'Q}>|I_B٩&ՔQAMm: qk_!5+F3[O<pAZY{F h͐G#hwS?f7DM!U +rFPۜh+^$V'M*ylz)6rO3dqc]=gRߥ`i[ogLEgh*jɼ kzUpA0c| ׍ ;cɝT2.A5JKr7.NM̺rqq^ݤҫ2\4"wc!!2A:l|mzZH'\vyn. NB.ǎam{ߧUdh?4yJ^-2ߢpY"koל{U`e' Q}WRgnY*E'c%^׍3-ax;kN,1gѤvuGAc:bDC \gѤHl|e `&S)t-T$F&XhlfX <¬R)]%? 2tQĢK3hOA( I0WX췦e$+XXBW!: ǗHK[meCRvLco˻tRfiSЀox;8| i 6s3b{mgtGvaOIr2^0wx>IPHN/a ;Y.6nø%t]GG=?t@ؚe_Nݰˇ;_S)ms;f3 9w "o3SSjFy= J+7b20Kb u!FFKs_9GPEslЙ#{0Sh@{۩V"NӿmJɔN9gSdԾ.2\9uZ%; \ ut$ XgZ ^*|\τ̉w,.1ξDOF^{VG\3{!͚0}{ŸK:_o&lKWۊhJt w+O%gݫebm z=6.) 0{a'z+?4\NG8|}GSrA\xU u]89`.uj`w,[ć8:J,/v$?6=FK鲺0h-u`l>qt8NA9 $yAޟN#`:J"bVǾHT ʰTR_}`}5:f&MiÒ%o hJMll"sپ/)35sLDp`z\g}"_~w|EGJy; %Tcr.ebڢ倳EŻ/BɨzJX#pm3N%شUR 8SMBp;baAG!)Ma%WN*SƲO?EҵB~h7:zte75ԩPB"+!^ X.&dYT<.XCĜU'4H$Z1ƴZn4X) ay4}wvi}8a6 *BP'`2gkI|^k+ ^ 6 y~"Cq%S4 NLRH䶿렔?It]ֶ 9hQ[R4QK\"ءԇUwTƴ1PJ^̼<֙7+˚(>`tԧψ? &rku'5x54Pײz]~?XJx7Dpguڕ ŷ;YwA)VN'?+L@D~6hq>9|<Mes?;/ >)l+6=H;@fzԾOe =S>ҽ=G@_IN7m['o~0oX W!(Ē=FSā'wb߻'4E -x <vx-5jCE,Zy 09M3unw;#xd 7pG瘞@K ~!ޓ5 2ŨwΗW'++c5d '@o2/GP9!LsxI*)}셔ڣyё}H'fif5"| }<~Nt4@K x+1Xj0:DV8#2@)E`@ϬJsȪ7d=I։e1;;&иzXc^9!h  {iMhZQ E(;ZÁyEXc}nR=Z7"1d+w -O)|k.N\Z7/ec<4+:;iJg. N wOX34 {VNt'$P)̮+v*-fgI6||4O7rǬa.Óc Z^h(08 _#"LkI%3|_SFպ]Ƭ8as+ b;ub?NB$A[/ m>]! py㕏, ShⳒ_jFmnnh)w=6r8 P3zjc-qS Iij||q(0*ȒS%]2RH) G6 d !s`a 㨀(( gr(f 6=_n@i@IJqob6*G~s:۟Ǜ<.G޸z}zB ^ zH+ I=Z>WPn |ZQ3W D_aPiŏo9i}:JtR=JVGB[Co?DWпEtf}i BfD%PF.I%T\L >N74/tڑL4ۘ ;#cVe`&2!pBo[n;!tc$*"vjvP"OQ@FHݺxev&Sc(wu!RAPuMBg=EjxKPZƆ Ip.Kr~ B5\W؀xfCTNUJ窽W_vEJi۔ecr.B_#EjV͐LcTVcU~_<>\>KJ?n]RRs9~^eߧU֩w^g*t +܊w5m!.4־mćuguôYE] `pB%/@2^&FsR+y/^rn`\=Ё l l\Xk+UIꭠ?ϮBQ|V M0c*P`7ڲ֒@;~>CeҏyQ*`&w.BGTLM1$V2;PFzMx <4]^1nV=} eM02>%ۙ\kd;V+DЏg:4$˥Y%;BWMF!WCUH?v:[ڠ$P7*1, V,@''0U MjQ^P=lXl@_T/r*j1W,A֜堽 DIG0+J"ְw-̢ڙ-)*!S;"na+,ݿ j4t!jeHŀ.$JL4KYh,Q?R_V($Q,` 7K,o]=|ȎG;_ 틡}<"}β{#}wY;C\7Ɩ ~ȿ5QzYo:(ZBPmGSJpQJt#OP& 3:Уa@Rhl-#XIn\dtnC&cL`LD*f2ٹ-E}ː W)QЄl6j#b xIj ٴ>|0d5qyP 1U;ɦVG'gnJ(`,&4hsYW*i !8[{H0Z()LQ2sTcu}_i]]]]U f'>K{-Í]ߖFD(7uakD֢Edzg5a8yVaqe-;Cʟ`)y>I ~OA^8xE=,VO2p$_奊-8| ٿ<{XnK..+22x!ZoӜD).: :!s3sdpHhU|j4u:!s&IZ u(˛G- X+dm@sT`?acbW(*8/w-SfjjxtUj<e{~Ji); 7&9_#r1b%}j4Mfӕ_О@Ǎ!ܤާdbhr1˘v|bLo"V@I@b/wfw̨_,=.'^g~ݨ0~K rߴ@s`#J;ʀarze¬;)W|:]ōSqg=^v6&iR)30s ?`shlM$Gٓ:&kԯWV fs~=Y4S~j nL㽕|@Z]Q7zgaR NYOP{>8l3qҴ\W4 R"Gr:Wy[~}; ,nţDF2Ο҅@uA;Y2B9rǩ zRz} ' U3-P!,R?˥l1Ji&+y#XspDa,`Oʑy8 h6'q-n[dA 2ޙզ<W|,~Eugʛ_0lPq,/H(ćUahbxb$Ah|lO)xgź&Ipo.x 7BtMXH絊 \Q\\wmJ$dqC$ uSePAؾg3fJ}^zr#C;-3mC&^1UB"r0˙W0potqak?Y4nJC 6i;|xka;3:z΢9G:"pz%MPRd^ExE?ç[7]_MOTmktN{%HiWޒM25%1QL1Oga#w)[B#Rk܈u8~]<#0\id -%@ax2/|$S; 5Ͳ9ySWfw9d3 7g¢X&%_J.9"YSi<=X7(<Zq} t@(Khi [`b`4ET4%̨|+μMNeAՂrBiD3V9aO+NE<$Ȁۥ˽?{/J6 d7LȔs9d,7btJ-UcZ.I%7w]OudJU %(fvNym'6xji~W}A3]oJ&C$A v G\Zޙvd&W56U%F`t(iYYkuxiRHrI,Q2 7cJ굩,tUL0p.!5ޯ-*t05Kjccj#,[G`^FU͓A5?;(:d:, |nVlN$M_ _xqc䀬V.$L=JKPy{f8|:o|8OIĔ@ېaZR8q #kk ~.ɚीФoCҏiݨ2:4?f`Jm 7QVxX1"Ɍ&3PyлͥD՜4n&SIRD[ē施~ HNAߖ$U&` ϙ39WqGmۈ1۠tMȃxz1.@ZIa0@|2a& ^R.@΁CRWT(Żusd=8 k m]Hߑsj7 ׺*+Yvy4::Z90bٕ62v4Մ\] ӳ԰j* z%T=- yx.xݏP]M[q HeMOf&[]/tfh;E;\rh>t%xK"Ju6X.%P2o_0P@Avϵ\' *k@ȹ5Om q5:;ȿ6h31l#EI3qGx|E0`Ox2ᰁص_ "13Zd"MkzY*Dh Če_5Ms~68+s^ns!V2 niq!DvDKŞ_So[JPzQAC # #G)<40v,^OֿnoU5b f1<=ڊmnH~ 3J!GmtLT*-v`"6!RȄy%Im/g88&FcM@ĕu(p ^z_.on6U_?c: 6q!rΓ/^3zTe<&}|3oyu ,t]H f* «ăڙ=p) ݋ Qȹ%'0FF?2BæM7)-^g'XbZH3QR}8|42GIWWS_pAsV`}`γB?v3!xyrLM.W4.r@zIZ>tɍ| Z wf*h ;nXr9Ntֿ*wg=v(ʝ 9EpSh a#Nڦu_B*J/]'bzDaUB'GЍE6;ͷx΀8m4;^Uبi%]!}3Mi! ͚6]ZuI-l79~&jdϡpZ2_~cu+1]( W`;嶑> ai/buS6^ ^~η`Z;Z DZ4V`SWlѣT+_ s!5oKhY,ƇvMk)h9iKbl ]L⴮nu_3+8jːus~4C] b;(@gT(L2K3<6V^#ήpa ;WcӺ\M#&ZHJ @]^?oqqAgVT,~q{0֮WthZ)rUNwfÊ%NH}|Eed" mrz^Ў6~J!1%;T$kdT39>jF} z"Be WP޿sْ#Ɉ@XUq%nIn?aJ} Sh= LJO>Ww#uf-V6DF+a.";>!U5ƶ#p-\0R t:F>3Dۄa /@$/lV[˜ۯ:j_ODž$JY7SL"gHW܊LK}6y$foEK.ܾ!|= g3O`*OQuP҅CC1XLEYrQyW]l ,i-bgxF4(TvZ?i_Il}682=ZGKX yf"i*{ b\8/ 6=7dJ;)s٠jGo#,$D,~rGo!{B]mIGvJ##qU/QL$$ !m,f`$mIԈw\5N\̼"*/g 5Ttm iJR{ # G ſEdpر_1r!ҼTt7 Vnĺ-@,ȾdC:{tF2iS *aJ@K&O9rvj:+DKK']4㽹.ƅ nB~/ґ,#N|K2LBc}\8YOsBLy}J^~BӂP7N!KORk-c?[f` /Ә~=BYCm䘼'ܒ^Һ1W2S .K 0GǸ.u (;4PPC'1vF-gm>saFlMȣfذ3կtBL(:I[8FFoZP<++ۀr;kwVeu "L=}W2¡ctʛ.act Vby2:/\vQ#4-[  O3}d%aptP6F/JScAҷtө[ Q P[+3 E+f:)usD~?L;皅ËgCg"旂 T/?i 6sDP* +r'DM'BXj! 4+٧Ȫ Yim0 # =w&yfǓZ-psXwq4~&@AFwdI_ eU1Enu:# [\1NĜKe:@9g #Wb>{ji/Ku1I]m`Z.K~#Z;F=`]֒ tjො/xg#|>4<+PaƼ_MM[L,5%Li1qvѨ>Pngrg"̳Ņ4_TSM VhՇՀy_uFS8ʨ+Ml G+ թVl`O!3|+3\yގ>gܑs'R` f3f]6ݔ/ux z-[]04Xar{4qb:9gE^u4P!XRiE9h_wwO~OWI݋'==~M>ߓY~'|>w_=;;'_;I|=τx_gknyzs ߓO|'1GuR^K[W/;5z9/rKLYNyH0̭CXn0yshވ"u Zb='PUdF" 6v0^7^Vy%0PRwԖJg$g~3A bn4&^2W[pg;p'Av@YebgL>4{b&JFKgMTSN|R]2m/fzqcSPZH'Eyb7X>h=7Λ7ydmyJ~-FYճa^FoiRlُZs刚5k?J| & xKH5H[ '/ӂ ;jc굩UAe0ue^E3=ױ~}JFb[>lCw.:5%$='|%˔ֵ4x 6!D^@$]+??ԗWLlE+ժ&MQzҪI-hF4΃[M9P~-1t_/-e kw3i=_AU=bf q["@M]k yMLuMM|&%#s{Nq5Tr!Fd5I7~|s}< >?&[ȌdOxL@]Eٮ$S+e3b.Xc ~8xgO-& L!=e|kPKN+Xhso%FG˝ᄑcz\ͰВ3 "[&5?Tws,.\bw/8a`IRt.C  gP{Ob.IǕb)|nN"5f~7e֬y?"5"M"cak=.$޳m"u wS5EˉO'9fZwpլ9Ԝ71h*b CРdbxCxϯ!tbCygr %0Q % }X2Po#"!T.c\^x(rnXAiշAkXJ3~7xh/L|e]:`emdr\U['o^IJ {B x] mf> /ht̲o%='X~qB`@+2Gߋ#C`DW2嶹FǾ g oQ8M1,WB+Pt hyR0΃~dfiT65]Zn({.Ԕba Ro|of $XdIvdǟuIĬI~M b\Ge8۠Q0Л2]:@<ưA\ʟKR7k+wigG]p-TjZpLA_Ո0gj8Bԯ"%g?F ՘[?(~#Frii:}H*-[ZVZ{B7:L sbgwa.h\ [C]C(y!8az٩_q % N35)[ܻ A IۗI)O;]Q(r:\Ӗy'oB,Ͽd<ڤ,ub$ޓ#nkmo{ɗe+qIwRk,Jns.oacK) ]UlGgU-m4<֔/EL xJ2?"ᐃ_rD,~0`^FD _,› q 3Kthhcկ_"!޵  7}&4]U\11r߯S=b`,@_6$[[%֟k:F•lb957Ta)hMe; mfMf}uaNKiA,N[oWUZ8Uv> Tb{o*G::|wgG;J|lb _׫Jjɣ^ `1n3#;15&Y甬QC yLeT"|lEs&ϫ>W~/O_'Ơ>(̎NlU-5&P. P Xie?b)ViTrR|_US^;[B C[ie@).]B?ڥPݶRu MH/r(*_yH҄-DR1<2ȹ>XNcǏeE1@.JB!;.8p|EUuR1@ l.ЏtXrh4,Ѳgr(Lo%:ϸKg8n4nZLIWR5aB齎mC^4M9' h5kfGwZkD&[֝ZTSt:|BۑVG "܄FfJfrŎWetg?;:<3eLe8jdNT FE39L?e-Xb#d# ]8fxQ,:jN\ ՓޥӈO= ,-Tե\H#2:DO2ȗ:Dj+`D^6~m9gїꃷQ[35=F\-׎U&3O!N-*v)>%vNe|hN3L{]4`7w{^#uȚ "LMXB*ZoHC@rC]|p;:^P.X…u0a }(Ac>ɤ`AMG9 $W!`-Ra@wo de3tRͨZ[#"z'#S $w9DJRYə@}I Ym\%* ZZ* Xp?'sa+HrcO*nz|1G^ Xǹd[l_i7OܿI |'#4ꇭ_{\d9)( oBod)9-)Kд7CU$ z UzzԔCĸ'uط,T G%%P\Ot\+qOAGQ-u-D@ȝ4xQ p9ebNI';VwbwX)I N0-o4:/'4Nݜm iI]ux dm pYԼW*x`s9͇MzU+ 4xP= 9 I cHG{gm!-)*F&b/7UYǛ,,KR'q0my5hHEAxM!] Bo) r; 5w2BRN ,sJNyd0Q9Mݿo"+AVKKk8M /+'Ii=p܀[=kp4-+}f> ^!;=Ijwpl1K.t9y5LYnsŝ/0?T鿚QmXb4hcM_N0,slCT.]wH3d[OYQWEAIw.ziVnj1bL\F‚c% 3ft'n@czF)8t7h# wp5`ƷS{::ye BђTmV[զTgc$DɎ7/g Z[u3CϨ/9p- [tfQ~v5E'" Wb Uw;3jko=:_=`P7PϏ/x)RdsH'{E)M0h?2:_{)^98sKo˘2bE|ePZ3}g7|s{TP 3$Dn[S붴wXo9hObTbӐxt!MXޜF}i1gx^×fAro~RZW Bαݩ*1Nfqa|8KIt_. cYD],(4(5_o˄L@Pl@m3\BJ5(βOŗtlxiv&'ǐRwӛf68ߓk3!iI4|f)r^/1s!)\d6uoA| DZ:1LqW)#)"Nz%|B' Aӟey6$LE~+4 k 27@N"3 #?&ېy<*N+OuAp>?fc;Lrg DºSTk"@=YeX)+O6O76n2 W%Ke#Z.`YyZL0۠@ޠMȑErRHEHɸ2ݧ5E>[FuPi]^[=r|jI1;U_/~EunI&#+励S:qC? 5 / FW^,>ʮԑl}/w=CG0 /wu(bz֕ts?"N.$w.Y3JqIgt NM[N l"bkAU1@q!t19.Q06f`}śo$d 8T>uEK6PZaQn6QUzj:ssܤBh+S.f,. QLVnZzL\PG*>_nO}հqR <c, .aJ4yi71G>lxfñ;+Oip1JѤ+bX8ƭhї vPHB+*H[C,jRZޫSHS=MWsBI'dUI@.'7ڰ$"O*Uc(f0A+yi3mŲWkA`4oj"&|<a驶/wV{]`fI$~Gk fPUW;0G=yq:iu? Y2]7{]*ELBԓV@,^8 [&D ʑI)[tIEfJZH膟fP3͆D) b't' G(>/J$!JI>6.OnGhXi`"VD~v@~3m $W(I0Y4c)^FjF6EXI]>^96џ {ĴaݭZB>ۻѻΦ1x'mOvр4CE<:Rcʪg%m[4=igO*P:oNF;R..aʕzEO>Uz;#1=`:ʘ. Fk LZ(" Z2LLȱixYv998Yȗ4 }l،&1\܈1aU5 n`4k*Sg]j}וrF1w+G>;3O*MԻ^7&F7GipEY6uZx/{=7O8$zƉ!bj5~e bW9@/{ߦDAky9EҦ: 4‡E ''xF#Τ0{)EaެuBK!xJ٢@p6 !Zouaø N7˛$VvQt9ҡH=?/78' ꎒYρV?]O+/կmH8E/<-uV>Luq6CbV4a3a!)Bz ԬT5دQ^ţh fyf7 ФO ܯliCP6,՞ L/~»|vlZ%o[75boOE3Y2|8MM ^eDR|\+@mZ’û:L3$HTmX3R3t'*H.kT}$ɠX`_If 1ϵ)`B"ئ$ňz&4n83 ˠWk'Gvя/ѭ:?b?\}Tf\cu.a]1Movlook8Lhmvߜw6j 2 !@ςNVF%C/`vL@}?T oc(Ha*$NPifSJK'xkWQCG7Pn#TYZpe^qtpD2 %ˮP( ,\R΍s U?lFr<".tV :CU@1kt>#4i2S"U17ĢpAy)̙Q)_jp{M߿t#.[T>&֦3]o&x}X'i!0Cs,{[3/;C#9||S0Cf֧M/<xEl~s ~-#$ [<]f W3||ď\Wybjힲ L )P"A8Ze0 8 =Ǣ}l"S,ǍNB)"gWSo'&}4 v 's)Dck~# ؉k^+s2ײV$*ז=8CNW>HL,11k{)&+IcF1Қ_ 1p렭*]t8L3'oN!ؾN  ֛I9md eixJ4>r0 .}M`dxZ:F7((^^ؾWg;i(\8۰C͑oKPѐCJ' (u@ ,bZ)zIyh1U9`U@%t?#&g"Mnb\GI,Z")4p;&|vxvĜN+]#H۷jРDH+x9$1|iD\id;tǠ(gXߗ/Wz쩱1}aڋQ+qsl}œk ҂=٫O<>p=!IDj˳[MZ& %0WET罧a'ڝ3:a[*Y-PwAFof/j1c:4y-;Oe[%("üu0P*SBH~OIj=%+МJoX_=dxxSIH1Y`~`H?; O-Ae3Feަ< @+3RәF\,|ƭ쁁{~cIKq&x wY6xƪ|rf L"lWᩭksXyaxϙp~ b2uc=K"^X ЀԼoUƝ_il7 C5Qm`QBkRE >Ǎ |w fGLGaxw7F6@Bk4{큛TPՕ{"o"UZ \Z!Ky S_Q5x^GL\ͼ&> R$F{Ò+Y:NDКy;nM-&˰/W;Y8zz19-X ą.ٶe򯬦.mZe"hDԊ[5"%LԸ :N[ku\G1q#{ݝ`Jl-̚eqs= {\='+kGx8:"t'k6WmyRD1 pM!~y]VGwviDI݊=q@lQMN2{}r-f41^[0_p-y;ov)B>'#@49ۦ@>MA9l k.TITS)[V[J[1 jCƐx6sId`Ewv !* +a噁' 0 A8o:,{⚈~|9Ms9 cR]%߀oY%rR=|{nI|VTX"CLٿ$,Mohm,18 c8(m(8A?ˈZ',&FQ+0wA$ZԓZD_U )&튟ʴŸ0䃠@(ӌ ~6+O6D'&'LzÞDnw RAs-wqSz|ӹO/l&m>VI2XRO*}rHَ2$osmXu2-,rEG\Bq>T gGYCXŒګ-pgFRO{p߹e㯐LjEVV]?\yX l`4\ Z8G,K58:|= MI sp+[Gߝ  /.<9 S%e]yLE G~~1N_$KHbV4LYZϰ>9| D0DqJrX&vqh"DGP[={=ryr\H$xa|kvKc@~=SY5r?wGbQƧd'W :ZRx3BEU?b*bH7F\{G#Tx(&3V\2^~,0@3b`CL>;#( p  cج}C=j.S[A,6'+~?ΓYt;3r|Pτ|Ad"™^99˩en[ݨQ;Z\:7pIj½+3C*&#[gӞF ӊ(K=ڀynчR /DhLU<^x꾎+!o9pGA2ƍmK˳rAP< V?ܽ%0(G "jg&lJ5Z/-CA$\5]akҍdbx`VѲS#DZS*b`KHd׎(spU1Pq$ٔ£]W&=\iT8d!Q>+AIFi;OA >v,A2L y ~չƮW2Q`Eps@Ѻtl{zVq]whkRRq,1 G kONӛ[E";w݋ s I^l_ނ3-R'>tM䶁+]7DI0yd" 0\NR)Eߍߠ¾9/]|C}qAtOS`<JYcNϛcIkA%,P?$MZ/TJ ŊhVn+TaGfB^@Z۹opUyk`R {\b09?:?RjL8sn8=p3ߍC2.I~@E8[JqK̓9.aY98g1d CaYTBk<Susn" 0/lNuub-n;ߎ㫶eo> Wy9ã3u~ Xf-TICh׺7A)C~ތ#Yѕǝm :\qA߫=4KxcdV5n?Ѫ s%FcL"p:cs6Pb&6fc~;t;DHYOCফD?$Ǩ`R|?dy9*-w W:qrz B$/}u2l]c=}qa GPt9Ѷ',28Yiϛ]Se}\$:䌔~r-Dt3RhLm,FC ll|q0iKIv^jE>X+ ths$07&r3#֤ MӔ\,Z#[R?&/dQ.3F8hvx/2Pљg/1C+ɂVnU/Y.3X !lbH)BMTVíTW#VvQJ;ҤmAd, mݚi{J 'nFRK.Cb`!ˍnUK-䙀7YJ6G?%K~~!˺{c;1.(~Yى8|~Ycws3'^Z#)wk ;Ba]F:G#eTOmU9 Z#D ضS;+s"NZ:U&kcm|'?T#r+AY mZYO{ yLUV:]znմs'> Yָ UBGwTn7K>F1ŢPCz'*m|xS1c9.?GN03<xFpvm' fomo}<غdj#Wm ;CaoȄKLulisWj5L~QH{a 8ĆR # ֌Cql]yc"N%&+,'?96>&4R}a.j6@l8iKLW< #R&`AėRlVBN%A+u`FdlVUHN"wzg*mĒ3&TJ$TyO2j:i& OVAwzM5 `_J:cNմB_U_R[Re~E03hZww3.LJ^D(ztabNU͠tY5=Mŏk;vK(x~܍şQb*BŽ$L$8!ge_Eu`R%K<5dF[*Z^|ƌ&f" V ;x,L"2Q߆&2 2wP ZrPrs䄅!hrw\t>aS|UXHv-. T\[D%^$BTMj6@יwk)Bsӏ!F{oipZIx뉠[ |% nάGDd *qX_R|.qnl,PD gUx~¼I@-2WcNwjWHcJ!U\i 4{F]\Vt q}!E\9hфԾ={*1 h5r"0QݸDL2<- :s.E}gq# PL,¯U3 B{Y:Ck1ӜXO(嶗k)МmKOSfrҎNj&>fRI&in>d8Kd"]6~| ]9UKM4L.x> }{!{_\%N8ml=}6=2<v/a2xsAd A1>F5r_f"w^$oUo{H>>W8 5xn>9z3rHI,2|=hS魨0d>rXpOW3cwpwvA;*nW/ .PQuD+@*?:}E: ~$8ݬէ9f{)5δRA^ [vhKe%s -fL"-iF gq>Ӏ'AX` utsU7(G߼>|> ] bǴ1XvhÈM/c=VZagJUk9ðdؘ]=Sя _}v> h$!Q.M$ױ8dmۏ7]KV@( m9i6>{x#.*bEWIbǦpS1ɪg}*C؅j:>^4lU37"{,qk5/q>n͍j?e hO:1ʑDPtE^Tr eh9 o>ӃPLqw:qR:OFtD 3PGW9b4>).(yIZu"U" #Ձֻ"Ƒ}dx 3W i]yOAwT"`g xg \P螻ljXE_ 1uX.FR!vTڱm쿳2Fw& pFE7{ў$*} <oCi_fIZ&5qQt]}t%&=C SLa@@kJEH(ɢDKJoҖɹ+ ) oՅ}|Zt?}@c/xO_8wE.5~Hue(}u7 (h2wl2{ͮ"h<ײ fT❄&X*\/.GO$[=;Cs>⑖fB 0xP2e]FS6/[|ދ;n?sQ Jf/@ B`- YҊASTTO9r!i” ׼bhZU^Eb T*, c&IqmElL /AQʎ~1 A6 9.a)c\0ڙnN E4|jAd~%3/ܙQ^:'P$n=aZ~{9YK lPt/)լNtYnDv#Jbl%N6K/̏ՀH?h&c=&jDs鿺l W /iNP~_ڹBcu]OM{g3}[lQP0 !LEQ9kL-o.ĘT.O,F_1Xj>"  5\e3r,=iE!5S?L\&33o4Cs\pƗ}0 z0YF@X acĿ{Rk~c($;3π*yMF㾰8C͡(*c7l@KZ§M}f zA|Eb/}*]6L`__*>vB"س~ z$^]@E4u-ĸ4q~P2 %K'S<.$m?( h!+uz7ғv柡wԣkMr)S $m .>~gg-*"îF\!OH3ӶQU*G8ӵG 4cL)=]Á uVv΋+N[H]T'kOi-K!:~&C:hjY&u8&bߌGL \$uk`0|1V J#A~n1ˆ+ܠJ^8";8-E5T{j˶Zf/JΪ;ZrGo64`jd·X)I?Nvf(^/3ܽlPs<ؚEo!e&autݙ:Tܶs#0n3m f>p$zq&GALǏfٔ”86 FG&%y6ZW) P. Q^Kl.+G ~F$Ik|Wv6v˙A/2SyG*l)Zܩ-0!5̢ݑTg h*t8bE{uvW_߇L޲!&hPhz&(Ek Ѓb"˗h溩 ӏ\U<4J(UbW766FTqEK~M`"֌drב8F@QG^?^VOR>׋9P 54tNjwg!AY0e<}mWr&`FUE)d]@`GSqXIFk{)[CSZd;)ɉXIt;qx$ksuMAt{P9Uehײ8FӋ8v92Bv2]5f5HxM+s;oPmj&!jwW4`3ő.s+3b&MS~h`Q8߭^Kt0un=P-,׬=2Lz7+fʹg[1/d(bn~ /4ĝXLӶ8oo0vH{{|GD|“L BLV<ȑ)tZ2`t0K_a= ۋ 2~Py T a^殲g;[VOkB<1淛8dKVMtKU / 1}*Tt4b_] ے;DOy :w< 5_xM>B[bj0n+c֔7I囎Cg ^HWEh5DBZ]{Ԡ'&|p `п߃e T} /7'yGQ<0e;k~1 #k29"rp=P ĞrZdn&+?|HX.RuP \ujqxYf,x~ܧ91 6ybBN㓎9ejW;%K1/ճL*;̀eEiYO)F+=(vMe؏JBz69otb$ T0$a ȟ[oNX>{oT`p#QnW~ `CAvO&؈ H4 Ȝzm#'\b\=rV&x^~(C]d`*&th_qی*JK"=@A EEcx ? !cu(s[/)y.afDbǺWmϰOM'[7#E٬ޣ:(!0B[1#<\ _P,% eK襾9&׹ʹ`5AN[K0'Hh(m6'J'%9~ap :plIo#r)X am1#@Q[ςRUg:2V(UF^lޓAOIu*sgP,lTŲƭlhTihLn."%er7+:SP~@_5L kCFw7^^N0$or9?蹼^`o$P{{;gˆ=)5ZTg +s݆sr{ا rn9bvNxr_-y6 4|#P[I:͠IQ"z;-J],l3igpDl\.aEy3 mI͗8U K9gwXj>1V }]1au>F Xxpү9rIԋfv2{-.~MUEᜤ_D{`B,ITY>bA3yvabĄ( a7U;hm:h%eHOV 003cGsFTgL W{:l.xw58A՛3JHʈ\o2ѡ;+R4uĹd-"M(RhثVr[!6ްxxU=?k N,oY`ylb;kE #"JSucptNPEe6Vg;!aamB:So z:Id#}HVrAgwWvl;yMʅ@Q9/nvS-cZGpnއ}/e6Xʵ+LbAo1Z+"B ?b.^#ÂmLQ/5ﱭSVadc:յ^&wA`VykrkŬ,ƹ, ?_.B>_g W<{OEVU7Haxar%UFgl9R .C$ >1v ;jWa*Ms sZ5NC⽫L.a5B玶hjF'LXtWF34J}mN4 n}W/x^7-LCe̯'~vu(+|3ٶPJV]E WbSd6۪HawvqˬbJKuQ Muʺ.F v6"ϏWD#n|x_NVGl>Rpjsp)5mOf&q0=yoɓ a߲B/"Katu+!׌/ %?Jxw*)w#ګmOV.hHm1^U\qyb\1taI9D8w4FT3TiSȀR[WJc:; R8:'jI=^c֢x{G|MuTtdf&X 8^÷m6b:梼4Ue0qfj*ӗ<׆ n␚7/#QZ hϡ_r`ej >BNS: 6>J=_pVUq͛XXސΦ++[=EQO .O) E=,mڒWUlS^}F 2-Rڊ$A k} \:AdGL,יo7]Ib+y4-1HQVDP|$zKS}l&X*K4a_bb0O|] brMԨƳ?2?lAnkFrOװ4 K&Xb0x?1Y`ٳ{w`atTDˑ/?dBș|23`$G1[]+>ω2 )x TU̅3=ϛ(rMMs6wnAKy;ЏW6 ?xFe&O8!" @ .¥u~NrJɡi Csw O ۶d#TQ&,fQT2j|v?, wdGZmݪi[!CʯiYb]qu~BC:ꡦfhK$=_ٝn to0CmwRFEѽ(SOK%="yfʀty,"Eu vpSG1~9ֺ?oA6G F)y#3ξ62(^:@!xr&lXDXbltPדui}Ƌ)R':=xx- /: 'c!k d lG0dw./TKR%'H,qOES&q+cβxd9zCy=$oh7v!z0ԩFiGxBnls:yȣ(V#[ hisN^Łg Hl&`,Suɗ*$YYֆ}[MꃷR7Uck(wp~}WAC3BS #}bcAxIA%*GI?PG G6"`@b)NrX}![lU͡@z|Qk,Dt~`JY nD.˔;,B|ȍ-wv*W|Vj b0 զ<#vج:ʰUV3 \pLJӪ v(猑ia.u#vkrY [4tT(٬Qz:r'48i}M(Yr$PoNQ 7If;t)_&퐁la%¨ J-)VJqG_8aPk^;Vk2B ֞S<c&[hG$Msjejh'  X0g\YV~_v:ڠ[.|jٚ?;>NӦ4pw'&ΎSWSRaۭU{J붙4Z9A]t/Mm!v g,qeCOL]X$(}Xqd[ފHŦAz)7CjeN@l,!yHJ[we*=IGrbeTBՖc63P;Z &[kB̙݉S̍.nrydnX7*/xd'IB.[?.QpX;nytMΔBt]=Ttw S PƢ<舤e[ 6o:dccv.^Lz66\ꭠ$AL-]AcQR_ x0QV΅?ZB-oeV0 :v&lQ%Ra4fE/ ď-5tOp"^{׌4TfNnnClz⌦FqPcd|&_#u^3wZYkߕjUWGk-rֆm. M@|4\<# &Y.$nٟ,Aq#HA"9%W&m91a#/@# tn&J#`>9S~k۽o XjtMw" =r];PJR ]snI]u׮~OlNW=z8@`\A +勝3˻7O#iC1> {-_ U^n8?Qp@^ #C I ", ̻G}QzżG >(4}~K,ԔneӚ>65lY [)*`D[ʬb UF,˥Oݜ#տ=oO >MȈ\X_lALFS7P)9Jsq^,C=dCcX.&;?-WѬQe[ S?zJpah'F[̕iRvCHp~Y%*PN9@z6_x?6mZt~5>ٍfM]%̜]NM=jj0l/pg6k5b5z'^*_=8UD ZiL%{޳fK/qdbjx1Xh,y!n#)0*qw" =$p8Ԥ#09)%A<ڿJ^ͭܠ4:Um|D s/"j9v-te)Gxm//////////; SE4\bx-pzsI4R3Nb2v6OGןq.jdXr+ slSy{L@Ojg ~(1 *TfBr,Rer^'QjnH˪pQ.l$le}ureыIIT)tjQ;:1qTxQ&c,Djk~/PJl#f'iZ -m\EZkaQ s"6[i){l1aWGZo/omVVe <[],wl{9D"^*5g)OM"/eHn+$bJ vK/Cq+hQ$Ė~[M*TZ,z֛ |[m l)29^1[M<=SiŠc,h@I 6QqQ$+2k0c2ِpՊku8:yZ:=T(3,XY H^h]{i:Dz ,>YEeP?K #Kq-?d _m >k 7e<[O#D t>Bc g"%ފ] ]<EDzud5>jrعub#}˘ 9SYhM;78G[:N46cX:EΡ+<)>p~rhiw7&۸G_8"߶0AL#HaAWd :Vk-P L.I*L?>1xّXy#r'_U|1DX\+HᜊB+8B֟E{׉:}ExF7pa5]p.|m[$@#s(45#8i/ 4]6a;9IBHL'}t2Xfjcɶx)`.Nv\/N%'&.A 3ƶa:h 붳ibA69`3aZE\g_26(W3r orLiQNU Ғ֢ U`{PQe5K0cDpSS*w,.i_ IѦVj\8'ǝ PH3-8E8fM6RZZZ}XB,wralˉj;ˎY&t(@+Pq4yvnn Q`?) =v\ X~síO|BP$ʮb-FfϏw+W{0B?;[^^Bbyz$[;vX*__p\'&?<*YO)_>D9%)^E-y3hj". /bIW 2b 0@C29F%CjamK*N ^3!j*E&CFvo7 |Ӫ!4şI4gf'gIzWdTϓN-\9wu|@:tX w`]:Ƀ2aׯ`5Zfi>(SB )CpqfRo;'Y'JrŦ|v =$Tt#֖';PͲTV]ͺ솑vXK|Ւ #];"|>!MB &J{RQͷ-$ @-.paw[[ܔQ#ҔZ&*ݶ$ą _4Ѭrha>jvMJd|% 0SVzhDSP%1-6Қ)N"U-AVKHWw@9tOa#wsR~Ƣr{=G'Iuj23M~E8]N:ԋ >`w0Z-X®K7,o{d!$RZRjGuP4>Dmc),G\?YVHc߫Ÿr1x?>dՠJ!J1,W ?Q*P,C?: Hi W] g,Q F7P O}.%vEM9-Cü`D}^ 3|/7(dJHow$i+0Mf}!qݔ mN/]`hÂ[uG cIHW/wn8~'}ۊNL3UUp\:el:Ў 績\ݔY\zQ9%#œ=VJq[ի4Ԙ2ta"r"Mn5j@X4{GJV!rtT.J{52Q#(djirLFFٓnIċ|y'9;M[6ζxq(+nj,ޒ&JrnvIɈY ^<Zؘ,-@@tE v,>ݛM"zϼ 4>d6Xxb qxj7@eayu)XAـ}']kBP^&c¿y Νfni^r (`h _3u¸ʝ$޶pt.oQ)U;ɘ[LbO{rtB6nHEw)SKx$"WpVH7"CuPJ8& K)nJL, N HOX9]^>tOk)LT3vx5=B]z;0P~FwMZ΄N|L6FV=B{3ZDM4A S 6-k]EZ>x$X†ZkU(9VípҙdbƒP0+5HRV<w9 gN3hA+S4.BI7zDhGM:'J4-bۭ7Gԙod>K}3Y8euI W4GG4Kh eW%ZŰ때K[;5@KrCbIDGw["k6Cآ$DCMf68B`8X9"X2kTOifk/m¸%:+IF xKC;";= 0. GۃWSU ߟL^~Ġ>"bfѴCrl/ڇI rDMUOEQMZH(4H+vo(A"ukPл6u" "FdFQ@L$ቴoa|h}V U ?Ӏ8-7eb2$¦RTWp#oXpƞFRj]p FM!־1co각QBX ֚A,M, vq;Ý0l(ήG$2mxSws^'u?M*P}.tD#iu C!׉Ch/"\9Xtt.W ,S;\yDL+ }~w5n[-ڍBq+9 P"í:tܤeӛg` }C3@}DM}{?c&6r!cy'Q)ơ8l@O+W}@oBҳSQ,u.,VpݦjU/u>4U|'vl%c=ҖkN#}e|^$\A:Z=~ew@jQL[߯Mbʼ _<ʉ~.h Nɟ)+zTw|`?PPj(5'οYFPzD37ބaҀX'-Tejle[ qRG%p3{ph{tI*+q^D`l$# 8d+鏎G;gt[|u5u3VF}mρFP"*N,}HGdjb͉eX5Y,$2A΄P/O. '*qUt6ÿ EsPPU~3d4QuԊW`02e^eỳb}̖kmZ +hLp}ZfÌKf2wNo'uJ, iCP3.5W34W)P*qC1R)ϋy)nVh:@K¼k̯`Р=XqlDC?}~I̯Fw A=YϡIzLr_Ma,]!m:Ryȇ[E]1aUomCrn #5Zow:RiBxx}J0?Qn-Zk2(^կxwfK$6{DFM",i8/ QR\|ݹ&<>]ݞv;v2,k i鮍,^qyeYϔYC#ބeiQ.q7Twe/qf޾:@L5b3}j EhڑH3ÔC(YDLV$PqEvTw!^GRTbYBEhZoR(f3$n=sǬZeWA +.{Z7%zrOP6wj.hw:YQ4TLfqH3>e$D=T4_}EMvx+/#)Gբez:a v!27lXw}tf q<BU/b5ۆw8q9}eD ]Wt>cb@p_'6J~g'zMUfoq#3yAi{d(c(dz0lD$es|Cbds̓9߉3ʞsWf5 oo(C6ɣ):k^xhh"xA|*{L55_0V~zx TR)iMcisB9 K3w]qΥr^o: ~0jdIJ5M y⤕&$n<lNVxZ &T7, ֋Z*Vk0-bbe7LSs(OxԞG"Ga ޷9&}30xˆb v]XM ,7;>uQyjIV\Y2 ? w+ 3N#I3.O# N/NH|ֳjt0h5"IaKH#DA'ߥ;=Yx[F|חy;;e>7j"4Z Wj >=Df(~nW% q[=$TN2RjJ$4SP0$ŀUHU;HMhCG1ܐMvt} -[ذ0wŵt= ~B`Pn!A޺?zﱁz:K1r Sju1W,Yq'I 0zjqE=tDK [g!piK<Ciin]N6?X3~3o/*VQ9k(Mp}X em|Yl"b9MU;F3qo'xL,P!ZOUjR='Hdx7RO#peSFb4߉JQ"jr|}4Ȓe8x{lB6CEjl7zHu?=OЉU1]Re%Yp W!JEp*/p LohW&yQT'{Y;A*pp+4inO7zQg-T1jt囹cN:|NԫT<)RGaZ~|9;1WkRF9%$ n"YW;J>sk^$RV,\#-;Ǿc$*:7AV4)@_vfqPnH͊%1 9CCۮ 4"c4T'A逦L S5y0U81 樄̟Ģnl هf?Lai0H)&l>5¯=+%Zݜ`{6Bj4XKѦ/OF=j<`g`I^eTM ZGE$ 18# Krƴn ‡^Cjg{*-;e[%ppDl\w %u 0? rmH~ӅEw]$NQlTz7<բǫvUi]4wT˖}]c8;d!.NڷRGliε'^R^U78H<\P @v|ז IGAue{Hw [i5|`*ν"aige@E5Syoe')>4 s%KwӞ, Z H#^)ZTàX*u+aMP]oQ)mCOGju`k)3E` #2^bԸ`bW}{+] "/XFSiQh 0'6%p8Vsod w_;'sj3qEŠeꯣFb7X[r` ;)vzWm*`^P{V d[jL >H`J3LN ]8RsDdO,15Ep'{Ӑ#0)y>PONO&f83323bfC.qDG1I~?kw24yס6q@bf1"Ddgq¡[QKN[҃WMAJNpIc `Ƈ.)YPĥ?5N\cOOR_yҀ H=8c Ж)^DÈN FhR^9P`|77XP jnVX+bXdZPţ08/*r ɮTMCHn&I+ ]? 鉵eyhts?Z?`'`;& Ɇ=#2:EMP2nIѣ/( a雇ѝVl)ŜU?5RU^~ƀ fΈW /!s-WG!JDv׺DPDCEǵvBZ %.=>GDw ?:ytYZw>J*jTf=4Efn"J&rvJBXȷПI gW^E,1v ;Kql g#SV ?E Ǟ 7qh.=gF_~hrVZwe 6.odzDZo#׼A-q&.O@=^h;CEVo M zb<3&4-y$,N+ «(t DD8uk3shi'cyBKEG[şF4ػi7'`$}W<&r(= YT`r ]~ƅat(Bǥu# x+ >4Y5nKWm:SFLߔgTqM$A- DZH}{>0Yt|){~N[=/FSC Q+w@#E$5K0!+hDJtzgomջfP<pȔr ~i]IHkH8-?W7e=Ie*[foj hfqs^rE{dSSDL$X%9b--W#S+ca55!9k L`]EP@h+0ɛ\RwaB[;DzrFu>{ u Ew֧lnrM!U b QGO}N~$֭nTѮ(.\>|mvU/ {3$Hި@5n?}{C;ԋϬ.en\3\x.QL,b Rk#̐s߱ф`m {`.EO :bB0+qr,7F dl~rvZB.8>JGꎉWKwO vUoHI HB!-N0S> _#pBS l("e>LhmH9@ \[H#@YB9 ϋc4yvh!zo%kw=!y6-$HMMo kӧzF :L44= rS{e)_GhevMWLK=ʸ͏F=h4e)j GT"7#i5.CyqZp|z5\0oޡ7L=iXhlV*8_1h~Y Gir3jKypMPxcjV}C(ːJ#m+!RqN]2q98Q^8{a,QhY,o#U#T]㥒F ѮvHc|jȏ&IWj+ўKV6s%D0Saos;ǩ5cezf|>vsFսAUB[L<}KIcdiQDZEmtSZPb7;zU{FzBox~\S }H\)F(4s{8Sʣ4Ҁ:IerL!f0Vɑۥ9-]2Җ"cVӇ؆jlmI$7+qR 5V+1`$TEBu3&)IXݳ^Ckp]JLlw>ƀb]AD^=4ֻ"7̞Q%sC}LUd {N&ԁ :6#W&}L%Ա]: HY?2;\q FTqiH&ZUq /{sXme?kZڌclx:p5Gߡ/~S0;aO0=5rc9Ƅ>TZa~TUUʓI ebTa))RT 5Q3=Il>&D躒z[ 9Q1Ȧ,vBD-1-4g,3$pαONo!WHҢ1=`G}ٍK7?`QO T4XNelKdN` >gV=2 ςuq#YkD(LGgfȆ|ocgUS)F ВѺln=@ ]S-@U{?(HWQ21=)q<%2!&L>2?`}Mߠ2w#Vlx#EIx=PUG,Wx_\K=DKl'XqXb7 ψEBwM bܓ>4Z,yRcЉ&=c6鷏>.#t= ]"eoNSzyb֦bOXیcxD.̻byMbAPÏ:KSga9ù/;GgUi=衑*JU$)gRo )q argk@ٔ 3>E=v2sOC/(Fd+71`!lF S! uTNӃ8cUaG{(/O {FnL|Z"Luf^yl(WwX *NKP g͠ʡTAF`Mk\(y(i>^ ?!!RX{g{pz}&Tr! ̜4YOa|Az2֨b3ʌzj$tmFL-b1|.+c%YHw^/Wч rrbEFs9*F.xbT5qjy;Yuǽl2I 'jȝi, lE%̰gtXYj+=9` $KѯƗ51o_}L:w%5PM$Co˅O5eD_ ֨}n{Ny~Z*nh~)BYG+Odm#0ժgۘL*$+Ӛd/9֘y@ޝ)Q.,G"|㘲b"*޸+1ކ9MaA!w#vĈڅAᰅ.sM6Cx E/ptWGe2<LbU0h77\[>GfP٭g Mk`M9V;QNG:jߩHuԇPBp䝨 $1,BE~U#ʺ\f8 <@x2Wd#iPpwa4UA3ǃ h _d+"\h=ūXqe~G!(C@ zյW vOmYh$xݔgx<|](XS ZEǁ KeDzQ,BnJz /\ ,aCA|[ꓫQx}܃pd_2.yY?98kF!WvTTT_sϬ 4' AcX'PA_繟镽fJ :$'<#{T@Yd| Y@)Ddm.ϧxT/ k=q@vOZ w%dI v#}spƒ8$Fn4^]U)]pٝ$WsIS컒<@{Yڀd3t*ɒy<7*NzkŢiǘ=15`)ʚ,R\ ;a(#C<u43Б! -o=k ^[Q"HE%5ӊe!- RLUox{wȚqD4b~ !k:lz1sɵV8_٩h ax.-_%SH".M={!yM<"9f6K*L ӝ(Y ضj4A󺎍H&4*"V%N7P[ԅ g\[OU{&ƪZnRa s ;v'1F潺۫T .b_W;U&Q7+YLB w̖ XSVT)˙O}OATz;#.xj'֎nOTSȵ Nr ָ04n96M zK`+ ː-sCOMI-mOorC\{U˿UNas"υxe)Hݟ/L>3S^386BGZAK^䒠ٱAcqL+XI }2Թ!V;ju>e7P\{ ._͕<>(9W{|2  ]2z J )쐮ZIiT`NJGlBj&SR-E@ vƪ춗% m$?eW9bjl0 퓎xaݵ! دMEd1ލ+7XT8z#SY^#JfA?ߕ(H[E{D1_7T.Eۭ3…'пU!;Lm>,,/[NAM!GĢr> kء\+5%cȶ: f\.2h$"A!ܾ{|t!D7<) -N79^EJM/E NlwV 7}7PHA̤uVdedXhЅ4bJ&ԎԮ/xF?oqLM*Ѕ Bs &_\^V7mPcD㏶5hAAH])|,6mFc2+rdRb,c$^u3M9sKnӸݠ/={-s"9! fƦH!N[aA,G聢A]v1en\Z;D-Y\pPl I<8g5(MjdIf^M_W !^=-3"Q/A&g6jX0AICu mJ;=F2,m[EyQv?N\ yRoG *TrRؖ9+wqZW?,D.1_?2eoɔo2+B$U`FDsVK3+PKS lTi㸇?ҍJF-?6tG:m* scP .idøS_k-Aܟ2f:K ƦO='Cpm8 M}yÚ U7\#YҤ[ Qt^|y/=ʠ[ⱘӪPpuۙ*F= ]Ž_M ˣ. yU^/<308,{ w1G['yX}< nQ6:;0|ƭy/QR!釩"*ju$Vϕ#Ǽ Z#,U-ve0){>y"O|' nl31gl[P\؂:]AmGЋSm)-9 h l877y( SMϭ;ҜָZpX:`E Q 3ٵ>3M_DTGb>޺;bXq`TH7"'j~DŽ: +ĶuQkdrŮi$|dyY8#ܾe/A7..7AAfVѢīVҳ@|C u ܞR[X]_Q'Ue5I~r1ۥDڄí@j \2^5@Ǖ)8H~7]xӇ+o:yTQGg%lZLG`?v ^T刣UpC&p傜UBB+n:K$=V݊v˩i[b\~w%dMؒ+`7<\~}ߋvjywiB!JOiB/Fo$̗@_b{b ڪg 5Ч#|LŒ2ᴧ3~Ys/s8y 9̝=LԂM½')Ӛ NV:W_Q(lN)Z?b"5uCq룗Yvi&ݒݮNVGe&jK,_lʇGS.z}CK+05$?&ǡϵyCmf7LǦi<_ASnDrb29{o"ݩRtu)[R9 N~+vL`JbKK QoxO٭|bRȫ&.ؠ^A#[V±D/k܃Q:iOh~v/ dI]θj@jf կŏ\dv棦O 6 %]v}e|zzOU;B\=c)?,0T=WjWgψBun;A*ySbn_X )B: <{N烦 Ѧ Rsg80 GN!,AvrwF;SW֮(qMy+;]⃻lJ#Y3͒j;.l-o#0+s"[VryodM :˚w'r:(ܻm8 $<6dHeA2Cm3Cܭx"< F?ZczrG1Գ/m)nd%W[fOZӴ6O8I/7 `s4WaP$qeUU$OMY:n7WIg p,7BXJiFO"~3 K&NLPMɬ*ֱ;lGa:^0gJu#l'G<ILQ>fT4^?0ApX)q#[<#l,rwGo/-PJBoUK/25I\]gzՙǣaNv`ISay}v[ K_;uI^4zˉ3Ʒ pYpX™q Ogܵpk=-վ,ZAw.8:1251>Y푽Pgqx?\&L 7Ex-73҇:(0v0#|afj8gd"}Xz pF0צ[yM6L,u)BUze>;8骜OSInQPɹ+>6m}j],:&ĶC>vZ}jp=չ?xk^K(d^ă ^reaZ @SyXKf{@:LtZ?=8,1xxZ]zpJEw'@"MK&C%aGnk֡ P8MЁ[otR{]Y)1\MQD(`|٦ 'چȨdTN6(YI/Aim&8 o۹$rCi>q F%sr/ir]n.IO+3CB']+h~#nfR_[R¥򋇖C*UY@N3f}3rCl&PL5W֐?*o~]7moG8 V~b$EΈ#e*1!}H9&:_wwk5ߓrw_=K~OOj:Ͻ[qDW|ߓ_ל n]﷿Z~~o~~A[ziWz1GB"GaAboojrd$ɤ$O1s9h 뼰HP}xΤ.gt(Zx,i',0Â#m^8?O|hEL~hؼ7l H,㝒#oZr@f_% `#lj%b+*Q[$6r̠no3(|&D/ Μn9tmqP`_ZP\6Fy1;n&)gT:u,[z/&>$U#a" f ce[{m !!YOGq ,N8f2=7 = L}o谄h. l*`YP2;-']iآW G嶴/C~YVNoA`ҵPҰz!A \wp7cLG9< #94DU_7r`88~_ح {C.}Q /y^M1 > IAK˙98֗a\gpfrV 2.@頛9_;7tK6WJL]kHXڡj x0.~*iX-S$Yڰ h'xÛF~%p䋵Uno=h-]Iz+XU\c$(*0"IVv[찄<<߸9fQBuĜCĸm ҜCX*lq!eRQ]/N L|q 'L|60%Cq@}JdFB?PC"#Eg1z5Pqu7l&'! e!B:bW'o^IJ {B x] mf> /ht̲o%='X~qB`@+2Gߋ#C`DW2嶹FǾ g oQ8M1,WB+Pt hyR0΃~dfiT65]Zn({.Ԕba Ro|of $XdIvdǟuIĬI~M b\Ge8۠Q0Л2]:@<ưA\ʟKR7k+wigG]p-TjZpLA_Ո0gj8Bԯ"%g?F ՘[?(~#Frii:}H*-[ZVZ{B7:L sbgwa.h\ [C]C(y!8az٩_q % N35)[ܻ A IۗI)O;]Q(r:\Ӗy'oB,Ͽdwl'Cq0"N8 wR>py1`-Ih׹&A_GzQX{A}n.%?{+i#/awv W~/O_'Ơ>(̎NlU-5&P. P Xie?b)ViTrR|_US^;[B C[ie@p0H)!hwbdS R2uC}1>D]%e7Gx~q11\Z^'`% >>GnJF'G Q>0hȀ+T؊`Y[٠+`E"@HjWU|fu" {yA?Pi<պoط+ Ƴg>}ic8)A4-AD7KmrSl;WmR:ѧ1wG0' #Ӧ7ṿGEުΏoib26<:s +H-\6 ͻj4EN }eI3 "xFeFcgҾMB . *%1_2B0Ŧ4oyc8KB(f#Q~h(-^α.Ƨ0( su8)(by<\=Q֯_~tG6e|<wTt۬9! ,aW_8\pD)*3gƙ/ KVnA5G#KTƶ`<, rJ.rXBEY&1/Υ,>WR5aB齎mC^4M9' h5kfGwZkD&[֝ZTSt:|BۑVG "܄FfJfrŎWetg?;:<3eLe8jdNT FE39L?e-Xb#d# ]8fxQ,:jN\ ՓޥӈO= ,-Tե\H#2:DO2ȗ:Dj+`D^6~m9gїꃷQ[35=F\-׎U&3O!N-*v)>%vNe|hN3L{]4`7w{^#uȚ "LMXB*ZoHC@rC]|p;:^P.X…u0a }(Ac>ɤ`AMG9 $W!`-Ra@wo de3tRͨZ[#"z'#S $w9DJRYə@}I Ym\%* ZZ* Xp?'sa+HrcO*nz|1G^ Xǹd[l_i7OܿI |'#4ꇭ_{\d9)( oBod)9-)Kд7CU$ z UzzԔCĸ'uط,T G%%P\Ot\+qOAGQ-u-D@ȝ4xQ p9ebNI';VwbwX)I N0-o4:/'4Nݜm iI]ux dm pYԼW*x`s9͇MzU+ 4xP= 9 I cHG{gm!-)*F&b/7UYǛ,,KR'q0my5hHEAxM!] Bo) r; 5w2BRN ,sJNyd0Q9Mݿo"+AVKKk8M /+'I*ʑx>: {(pL1ld9Cr7JQ^ KqO׍*,ތz*QNd vm05ul X{ eQMR\$8eYq52ߟ!3S.]N.xwC=ukz]srn͇wJu '[eR :eçOz3N}؉8~Z_nQV9=cig-?" Wb Uw;AD(%zY @!cKGJ Kwlf39GӲCޟ3G>WKl4l"sI6p$VqX?}.*^*yQDzY}?itYG"kU6뇴C>4A 42T{+uQz-O{Ak9qg"BX-Pjd&4 G*1d.ת{qBb۳P|ר%,S?H ZL<1.Qa@/^WD;8b*L@(u5h)攠bzMp-@U vL1"Kb4 sÜ̹mDA|YP61E6@j`:c0Gv E9z|ԲhN唥.|A7ٲ4!do뒸<^z65ԑ'~;;h5{Aa(h(WTdOX`.īr[̱W7ކ ZSZ?T 5e'Aa-JÂ#P$~ Z²FB9@[$~$!ǟ48PS1msվ]<.6z+EeJӑ.OL腇yIUN)A* %hӟia&G%HPP&Ńqr D{qbPW%]L =<Xuf~]\c}s5e "wOvŪV3qEtd&1W)X';[ Z LϤPLh2vV,.TTzWan⬅TrkO 1؟ݔ#50mrXyOAW64Hx87.W]'<% n fݧ!J}fǴ5nc[e,dxZK.C2~@cxSQ{i<5FT*&xif٭ϝ;, NA12T)wBBHS~ @1А) ,jpux P3F.5瀥6N֛5[1M#nTVs yL6LN)"NzY.5 ?VmSP>!Dæ$j0,ŹkY-ln!0qs7zgRL99岩!R'aR bjAA;`/~a!?Zk`;_FلRWe]vҍ&+?_k*\~?|U)WD[ˤ})VY I/N#A-x5HtZ EV|ܓo=HZB[ tSTK`e)ݲH!?bܓv jAG욳>ChgD#ձu+ , naCԄ[unȭ4$ _O 2nRLoE Z(SaZ(̥Hb;K֍;x~Udc܅jҨvv/?5(=3w޳1mق *]{0)+85гU 3|9L9dZaXw+Ks%@ZCB 7U/#) L{aP_%BdPi/9msFű4_;ER+*koԖY1ۅU 7^2b}O ԲMvԉ?bW0VcRꕉKJ`9OpYȝy%?h#ZݪRRFkAlE>{P| Hj-|ӆ1s*oB]\m!8H<2W ADO,Ldfm9{ '!3_Ľw{]`fI$~Gk fPUW;0G=yq:iu? Y2]7{]*ELBԓV@,^8 [&D ʑI)[tIEfJZH膟fP3͆D) b't' G(>/J$!JI>6.OnGhXi`"VD~v@~3m $W(I0Y4c)^FjF6EXI]>^96џ {ĴaݭZB>ۻѻΦ1x'mOvр4CE<:Rcʪg%m[4=igO*P:oNF;R..aʕzEO>Uz;#1=`:ʘ. Fk LZ(" Z2LLȱixYv998Yȗ4 }l،&1\܈1aU5 n`4k*Sg]j}וrF1w+G>;3O*MԻ^7&F7GipEY6uZx/{=7O8$zƉ!bj5~e bW9@/{ߦDAky9EҦ: 4‡E ''xF#Τ0{)EaެuBK!xJ٢@p6 !Zouaø N7˛$VvQt9ҡH=?/78' ꎒYρV?]O+/կmH8E/<-uV>Luq6CbV4a3a!)Bz ԬT5دQ^ţh fyf7 ФO ܯliCP6,՞ L/~»|vlZ%o[75boOE3Y2|8MM ^eDR|\+@mZ’û:L3$HTmX3R3t'*H.kT}$ɠX`_If 1ϵ)`B"ئ$ňz&4n83 ˠWk'Gvя/ѭ:?b?\}Tf\cu.a]1Movlook8Lhmvߜw6j 2 !@ςNVF%C/`vL@}?T oc(Ha*$NPifSJK'xkWQCG7Pn#TYZpe^qtpD2 %ˮP( ,\R΍s U?lFr<".tV :CU@1kt>#4i2S"U17ĢpAy)̙Q)_jp{M߿t#.[T>&֦3]o&x}X'i!0Cs,{[3/;C#9||S0Cf֧M/<xEl~s ~-#$ [<]f W3||ď\Wybjힲ L )P"A8Ze0 8 =Ǣ}l"S,ǍNB)"gWSo'&}4 v 's)Dck~# ؉k^+s2ײV$*ז=8CNW>HL,11k{)&+IcF1Қ_ 1p렭*]t8L3'oN!ؾN  ֛I9md eixJ4>r0 .}M`dxZ:F7((^^ؾWg;i(\8۰C͑oKPѐCJ' (u@ ,bZ)zIy.RppeWp-p 0ߨci-(?yk7Gyޠ9O=]ujqb ڶg]1Br <="BGm'nR d(gʋZH4zpcg?$!B.t!Ӡ.ij̉8Q `51 hkhޓ#{tz{o%Q!?v=ǀ]*9i~Bxrj<Ϊ3kj-z{2NPE+FݫӪU!".W6xN؉X4gJsR5gηaZ}sVh]eĀƣRHg1w>4 BXĐsZWI2,=hUx"a%zQ=kՒ)°TSW_fo)d%?B~64kwFHԉV D.F]t W> ]@~htV4n-xb& t+nZ .vNm\r}n {BD T a{|X)Ϳk]}y&|ZI{ڶ0i]QabS\;qv)B>'#@49ۦ@>MA9lWy[v^=ﵝ0Dk^]"#lH ShMt h SuuH\T_K$r Pcl:EGے'*!aI})̽zϨTxk̩lxмD0N{3_\%݄j96&e:"ڀִ҅F b[oJD.WT@ЮFF+,mXu2-,rk$nn*L.2p 0G|K ("67D֯o OP}2iMP1I:Ƙ'A$R~sZZ9@<wQ#EOO۬Y1cpaitQb#Tr)f,$ {oȭz'"uTQG-!2́0t}W7'LS˗߄y+/<- ٮCR%hckeI&p~E)ԕNa,sj"è1GB\Cc. 'T6]:|.1\Μ mX!?&sumAζ#jS`T¹!>1Y/^~,0@3b`CL>;#( p  cج}C=j.S[A,6'+~?ΓYt;3r|Pτ|A-aLEq0Z)0:sp0*6ə fS6ɐcT: ':jv=IEob_܊OlǴ_ac΁{TCzzԛ xН{?g00x;V)q#9lCxп*X)7yrw0ޖ֍,O/‡l05޻bʂh ^ڼh ȵ 591)X@zBiNIP ۟h;dÂ9,d0"Z-LsiOUyFֿi6 *(SU>I_AIFi;OA >v,A2L y ~չƮW2Q`Eps@Ѻtl{zVq]whkRRq,1 G kONӛ[E";w݋ s I^l_ނ3-R'>tM䶁+]7DI0yd" 0\NR)Eߍߠ¾9/]|C}qAtOS`<JYcNϛcIkA%,P?$MZ/TJ ŊhVn+TaGfB^@Z۹opUyk`R {\b09?:?RjL8sn8=p3ߍC2.I~@E8[JqK̓9.aY98g1d CaYTBk<Susn" 0/lNuub-n;ߎ㫶eo> Wy9ã3u~ Xf-TICh׺7A)C~ތ#Yѕǝm :\qA߫=4KxcdV5n?Ѫ s%FcL"p:cs6Pb&6fc~;t;DHYOCফD?$Ǩ`R|?dy9*-w W:qrz B$/}u2l]c=}qa GPt9Ѷ',28Yiϛ]Se}\$:䌔~r-Dt3RhLm,FC ll|q0iKIv^jE>X+ ths$07&r3#֤ MӔ\,Z#[R?&/dQ.3F8hvx/2Pљg/1C+ɂVnU/Y.3X !lbH)BMTVíTW#VvQJ;ҤmAd, mݚi{J 'nFRK.Cb`!ˍnUK-䙀7YJ6G?%K~~!˺{c;1.(~Yى8|~Ycws3'^Z#)wk ;Ba]F:G#eTOmU9 Z#D ضS;+s"NZ:U&kcm|'?T#r+AY mZYO{ yLUV:]znմs'> Yָ UBGwTn7K>F1ŢPCz'*m|xS1c9.?GN03<xFpvm' fomo}<غdj#Wm ;CaoȄKLulisWj5L~QH{a 8ĆR # ֌Cql]yc"N%&+,'?96>&4R}a.j6@l8iKLW< #R&`AėRlVBN%A+u`FdlVUHN"wzg*mĒ3&TJ$TyO2j:i& OVAwzM5 `_J:cNմB_U_R[Re~E03hZww3.LJ^D(ztabNU͠tY5=Mŏk;vK(x~܍şQb*BŽ$L$8!ge_Eu`R%K<5dF[*Z^|ƌ&f" V ;x,L"2Q߆&2 2wP ZrPrs䄅!hrw\t>aS|UXHv-. T\[D%^$BTMj6@יwk)Bsӏ!F{oipZIx뉠[ |% nάGDd *qX_R|.qnl,PD gUx~¼I@-2WcNwjWHcJ!U\i 4{F]\Vt q}!E\9hфԾ={*1 h5r"0QݸDL2<- :s.E}gq# PL,¯U3 B{Y:Ck1ӜXO(嶗k)МmKOSfrҎNj&>fRI&in>d8Kd"]6~| ]9UKM4L.x> }{!{_\%N8ml=}6=2<v/a2xsAd A1>F5r_f"w^$oUo{H>>W8 5xn>9z3rHI,2|=hS魨0d>rXpOW3cwpwvA;*nW/ .PQuD+@*?:}E: ~$8ݬէ9f{)5δRA^ [vhKe%s -fL"-iF gq>Ӏ'AX` utsU7(G߼>|> ̈gQE!3rN;Zz-2y Q)=NCI/_Vod[UݧtWL)nLŸF+9lM nha y¶Qм{*?mEZ&Jۂ?'?Bϓ r/O_ȸj]! #/͇VsP L{1Af*Z>$ufV_kAOEإ *H>c{/^h7@gm*f[#r WfAْ{}(j0J?e hO:1ʑDPtE^Tr eh9 o>ӃPLqw:qR:OFtD 3PGW9b4>).(yIZu"U" #Ձֻ"Ƒ}dx 3W i]yOAwT"`g xg \P螻ljXE_ 1uX.FR!vTڱm쿳2Fw& pFE7{ў$*} <oCi_fIZ&5qQt]}t%&=C SLa@@kJEH(ɢDKJoҖɹ+ ) oՅ}|Zt?}@c/xO_8wE.5~Hue(}u7 (h2wl2{ͮ"h<ײ fT❄&X*\/.GO$[=;Cs>⑖fB 0xP2e]FS6/[|ދ;n?sQ Jf/@ B`- YҊASTTO9r!i” ׼bhZU^Eb T*, c&IqmElL /AQʎ~1 A6 9.a)c\0ڙnN E4|jAd~%3/ܙQ^:'P$n=aZ~{9YK lPt/)լNtYnDv#Jbl%N6K/̏ՀH?h&c=&jDs鿺l W /iNP~_ڹBcu]OM{g3}[lQP0 !LEQ9kL-o.ĘT.O,F_1Xj>"  5\e3r,=iE!5S?Lz{8<5=[NÝ̞k'(3 ^gIqġ4h͘H86mf rm 4$_qWkژ/1 }-Bep ޣ ʩIuY4j_Z t% "n'j!4 |~J,"z CKX#O~jj `w-'9'zljO2N>|q]7]r0lR4Y8tU&Ol(nEL+28ߝˠ@yNXS">:Utf8 VG}-R,xOIZ k9-]֊Ēl6h|p9-ǴHZn>"j, 6OmױmY2*~ pHI (tC٪ٔv]4Q7?;R_7uYd50w6$Ľl8a6j(eWs):`B`(7xB;?y]:o%HT \Ds',|'Sx7;L OTjf_FʾYM tNMc^{J1Sv"d#xOj7"ǪBsAfM>RDJk] Z\f uF 7y閸: >apx V Zݽ%(6ؚإ9-tބz?X}+]Jq|~iG| "57B4&rE71)6&ewNC?VvrXzGFo@Yf{BAyYe&ߩ/8 qV2Wke|,'$E}&8| 6{BOSts 8-RC8+mJȝ`ZxJ-wBl9c!䛳B}r~9Z-JZ*N)LT奲kMc2HN]0ެ.hT4Oѷx@B,h|. p*w#{x|6Ӆ'yc wo@}6"oܗB6G-Ȧ-CQOHjm CKmk^[ !!(gA #)1)z۩dS+-Pm*tj%4^#œbЂ-v5 9̓]憽&D߭Ӵn;e@T%Y)찶0Ӂw(;Y0k6vZkLC77'#zM'DZGn=TL5C`-YL]`ƩXKeJ!]=?v"{ ni Tu Xk]q/!%s )^U>!j+thc}aӜ5Bl|hvedLL{(9盻]SeǵtWO`繠=''պ"'dl₞r@Z7IѨb|[uF@֭}c^ V??7v|Ԕ:֦.٢=ʧRa7r)E= рB]4.p0nEJV3)F ZlNMQn=UX%-+n&qPUNU>'^&e@P,cΔɕ(*XuGR;;V:#žf٠3"HI?iɿdGT> W]|w M+ٍ \LDd*y F_ﯟO>x?FɁT}3 "$ 4@;G`G=- WڈM [$5:j|riueg <ȈZ e'&$ǘpUpJm*:+ ZP.Ìa`/ޤ+@d-onx]DCG nC,:𿐭 4Wp]<ꇫnO~0Tԑ ziۏ5ŮC`u q^r+7фkED ²TvZS@I^:N !)}NI˛eswbp5VIp[.NEs =ŧNC#G"bR*؄K;<<>AezO0Yͺ]F8l6H'9Ar_ x{b4w"R|8zZͽZBsix_]Sw^fOtx]k=rzVى?ĴqLkgPE]*Q jXXL*ҫ7،ԏB^􀣿#_xvT3.:lT M ڦSzF#$ad9YW+b#`F~Ik&HAMŧwmR9S="k= -ڟi4ƜQCUTmxL1_`a7Os.SJxʉnm{8V$|Yrot,rv"\Z@99-g-ods߇θB+'"VYo.?y;sNPvov(y슶v,ďT ?Za+*i}YxϨo'IGKR%cl Repn~ʶG#"-3X_+%g00a#f.BpR0̔0F"\Bˊ$c?JWY?1уdP*ZeU\%j̒" ZNi&Fl퍌5G{j?+JlRPGr(awfWj;m9"fLC"x:dގ03`jH5&)9M^74d4XM  Մ}@armYMa=N&#?o |K@{_e+t )Ҷl2zG{\ש6 pǎ`e a'&a$L#bBFW<7 ;צ#EW xjtA ׅ؜DiYGR~>,@l^Wo+Z_+(:7΃p't:oV:b `n|Uy8-sH S[Î>1|D5|zY{eSCy=Hh ;GTP0 |4#?"ϓ xb[ JR"8?D*Ok>= c+f* %: syը-ceW~$,]H9GՏBW ̸xOZɶwxeXa"N: ݩa:ktbț hbwc''3R]vy'/RS%-An+H%\!)+ 'd@*\:HYě%*( c̫uUwE`q6kGdd2`pB-NMXd˖ ؍[ʪcG })nN /u-ioS#sn<43oS^qf*"v !cLr# *-Le{?Ut~!E5wS^|:Jj/-MKM;S¾IfG Qefѱۛ :l d9"4MnKuqu~ E0k*T m 6CE6 aӶ7+- O͛f~%,^X-o?(5E] v5| eC ?TPVوzQ_(92Yz-(0TOVRw@fkWHxb}2[wS~fyⱼ{xQ*KeGP&|z۶+Ip{fzțh_怌7hMܨݎyWș-Rt8(h 1A .d?E9d1-SDgtOtn1sy\IN\ې~U-5)ج/XJ _fYZ鞍[ Rc3Z4oyp^$0|CIFN{x Qg{jפ~>,;֬' oLDU'd1h](Bm@nuxe{Ӹ W1$Eآh (Q翚ƗOE/ŧ_+g[PoBieJ }C^4Z]z7߾F}irlFk۬+` jE.{X0Ԉ!\n#:~ U,#e1l|{;:]啨6@w} IvYLaJzL$J%uo.ʆ T% DǚrX#;np(!KS1zRdIVu$SυuRܾ2ՖS츕fɍص LkLV9mܮӗlT4Et_Yc1,Xl)&zE>Z8eh޿c);{ 5\ǧ-X[Pi 0"+7O{] 7J p\,{20#5gQ;(| Vll(+]u,JGi$DZٔL+P@ֳ2x)D/hNPURouW^ݓgmkG ߮fE|x'yB1KoZ&;x3bge7S&hףZ{Fo1pmlꏭ\hvkwQe..xX$c<*ŲęJ+^b v3T5ی}@fA!M+zuU9"MvyU/߈2?^{':ဨQ6)u_1/)2:2ݕXTA@ =*ko\mTcfs+TU~@|O5 =GMq Y=S2{~X3!|V}6_h,R\1W5U`;( M R;?4wP4:7U+$1N@jQʹ̥!,ɄnZtTљs=9G8>WKNRf 2]oFo>6fr_կ嗎?~W10Ev_]g N…mhE8wϰzIAܩQk,r_ff vÕ) tZ R :i@)c2>ixy\N#wx8,Dx N`󃬐 M9}hxL>jAVe}~KPS2_ɷ|> A~ΐ>hKU 붥}Q#]?G*CWt" !((&7]QsU%X_${c}<:>@ӻnn]@̈́ 6xJEhL+Pi3 rAаb*(plE=Jb,6eA!C*¼F0i̴CU/hKn6q&1+"k2At`ۙnȗ{D{/(Di05Ht X9Tj-$z A!΁[RkdFsU6螈S1Tҳd/Ua~h`ߩ2Ḭ./_Wk>s=H{ HoYʾ$/*) X0(3C#!QjڝHQTFTC1غ:fJG$TO$?ύMTP(&yV腾oTnnۄ~+8G22v#a0lHh:*<b*{Suh _IH<2X -D y,kv粷?5i]z.gī)/!]`c -'+^~9Ԁ=fJ_Ҙ]:5?ƀe{A|_d]vDUl U#pn؏/Y1RXa;<`CG 8lwrԳh@zZhB\*@xpoX;DߣX 0 S =N Qr ,b[ꫩ%.<ⱳoy\BB>I}#46&3ے[kG?6W{SSw'VV֣o3[ƎwZjjCu.= * }t8ں,C,Biw|`}r/maҫ2vjYq# bs3j<־'|+Xy@%^&}#!|حQ8h BȻHgn(i/^[ԦAd}W28`,7\<4\y/,aKbb]o@W5\1y0z$:Vz4zǕv8!joUpZs񥦳k"6@u;ɧhxC;*~q~e &zf'N7M7$b\|1t1O3sr9xiRXM>;. ܀@mY2 )KY׸mR%Pdn@)(3[LΆ2rZLy;e ؍Sã8~RM#h6q_([`]yJ&\Ǜm漂?kdEd?[{87M4(:[G\}Y%)?u " rb)bRƒ^K%q͆䶞ȁmB|ąXsu AkiJ oO.1I:0v\0OG5;GFBcm.ٴ[| 4=/3Шݤ2f [X!"zI;56dj: $-'~0$FF fZUStcۆ_UA'W80=xbG̯UtA`u}t2D?Õ'zoP ѢJ`$!*A^lF賈/MH=۶=wG kr7<_ZB>PH*RuD/\xPJUӯ [%8(d(ފ:geD{Ak"iC=E+l96"P`wzǧ'n75X #Nb; ƭ 0^ᰌ9%dY@jS_n 89`<(;(7nPe! }GktIBH 3R6lK0 Lk|rOncb6 @:/˰ͭXլx @0 AQ(qs+bN@*Il[< *Ap^B͵~"Be}v:fk5<<0qLSuqXd6ľrJ`u n Uu-E'-lҍgQA}\o"CxyO]jY4#edRT2d'Mk4A_e"ܘ>hO%>rl^)<BfFw(o;|e22hv$p4WFo2u q6RCXo#dAV(-άMqU%\2HV'3!vL)E "sFLi9wcp3 "kم{ &۫(<yl=:<<ӱĽf~CYj&{,~sui-*Sa-CcJkّhlYN:#=JN/n&#Ȧ‚8y1^pF 7B\)ABJZN0j?/iq%H!Ƴps<]]:bBmbO^U>'ĝ'9jS3+`*Aq-ӵ7D =m %G^)GOXsA X?odS"Ѐ_8YE>(NK(m'*C cͷkf\*&&+'H'QS]d퐋ī \DDz:ܵzah/ h /D_Tl۫Qҿ[IrtyS&?N|ԒT Ry#J0"l;c~Pz~n .Q׾i2HɪsSTgpGHTu]v%BչG0ʊM[ű!;{kveu)8\BDbVӌG;%(Ql,@NJO-0sXCʹm kq:+ٗzfFy ~ru>`ݯ~x!AD}!suВI^\ dIDOmc_U€YpRq aX=ZH=n N Tx@@ZV7ۈ,LϽWGi.[`@WTJ4ʢ zE⿊k;(V &K=OB.ܜ9`?w4@N;ɜq ğB=8!2 ;ak5`~PZFZ̦vmˊh,{{u~$.\DNx=b 6wb{9igDphB~ ޅXKQ>B҇IP@YW>, 2vc\Mįmz!KuL/}C$Z2~51-o8+`/Ꝅx.F ټo&$sM)vՍD`a&mjfסQJ?wZ4A2'ItQ54gbrEԏ'FoYӉ@yc?J E6w88>h'l8kt.Rca~Z 7KoBqcVЉ U'0b噛 eJQ\YhUށC_sbJzO*gIWR\r"=PU ?|cYN-^Ń1fbaUV! P>*VQw5f`гD;YFvD"# /ߧ(s75Dp7Ǎ<5.o5mz\k*ǴM'k(CybWYv|,V޾mwnz yN42##k }.;䦿FS8$@P/Soe ҹBf~ƱWP3_(?a xp0 t4sK[A.p\RF.Ф꣐,:we)$h7{W)ؒq7J,2t\sQÄM1wm}/P d]ʐtI P,8/PSy~(陀\{grF'?{K<*dkTPKخsR TV**%˞-8]> Y鏑Iߑ927L|5ƒus;N:}t8t ˳[9~eoNI ?~foÌTlW*wDnqf+Y쏹IÆ?yɜ& e8b8!a$T?/`X#t-/@`|6h,{_"T g Ϛ$hmv"L}oي;jh_|y^ m~>`# c Cm\`$EIQqArsp՚"v6Tp}Sp&{jg/@9ƓK,LMH 5O8lQ^ -FH'ҍ<]2}z*IםK(WGa0V^%itr,U\,V  6A?C yw m'DWC5<%ÜXr\A] QtG)"zQؾ«[cM?La0x5*[_=r\ ( I\3>e 3 xg6 G2,$pξK{ZOww }SGC[<o 3ڊ&JEHx1`C%,..~lA s{Ϙ};-t?27|o:58ưnpHjI8Zts_ŋjů >ddocCOn>ѩu ׋FN~z)HQ\>(!4 +^׾A.ǡ>vo'ڰ;Oy]ܣ3Sq @֗#w/^I.R:Q^xB#xJ'3{+uWWѴ UK_b7UƔaoYhIj$E#QxJ\* Ͼ*|1|h;߄ߌxr pVW6o|бһ5?$i9+*Bh(C@)9 O/Ex8*pkikmf81/(T'_]wqBA' Wg-21?4vK`^ akAWUݐVZ[:w6dHW&ڊ 8Tη<=O)N7tJ.PkQ2=g-Ie%)N0\`:=Q5fK#6ڶz)[Ĥl0=gSa;DRب(AWfOqp-] k$vr.n (9+H$Ǥ%~ۭʥe(d aP@ )`9 ^hg?iofYu v띅x)/ႼQFrCG'3ҘZtu`I=a @U}mLd}<xf`{!T1;ovɺJ;{죽0ۡ;^>W}OqhWGj:J*>՞ָC8IW\B`8TImƄ5QAGak2dqWӝ pVP* qSg <}cK"p2yqy0FPxe[YMQ)I쁡,[O$IAv;W~;n$F|CM>^aoUa wXlfna}ƹfE> #;̚<'I껕7śTVvgzJZs=Kz~$2yt7<9a {!ԅU4BND~u K嵜!MIk}b7ԛ2{2垯%UAɊhgn#"Rl9OhUid0J=] ğRW"}w͗  "^8tǢQNj]XK<2/0[.t.\RZa ǔTV{(i1rm7Gl,L2sAueoXEVEnM4i`nZ;%$spia^ԉ2:wF'u m5RZ|CޚIqDh[/sdqЌ6Q,T.ЮN](ihny9nO`wfĒ3;~! fSZ]do}d68+T%moo>M7icQH|3)B=&A?hFgKLYuF%U7~ RE.miY- PR=D0e`pqw|F%Mf@>&V!aG }/zhiIh1jav aI<$cg/¡Sq%e%i6 $0Q:Tzx̗ȻVNP` 2֌8E߯P@<`*ͷg@~oJvkN@):7Pޚm#1f۔[Z-%Ekb[fZ6݊3rci>_(P;-$5`46k(SxܘuJ}}*}=U9EgF3!9e*"ЯT%{6AԳ,w\eu7#.{y2ngwI٭Sk/~9`*v1B'?7B}W|@s61nIl'-T;H+IȨPm`kGkpɱwђ63Lcn=ȱFJwQvcLO5 iDJ鑧.K{1y g?o`7Is=U,xo`TXˤ_jEH8ylJ@y|q6z#@:{cWޯ{-6ɨ}8DE[^?5uW3c9]=co녪I *.W(}*7hs*` GgH D(7' yDꩮeRFF9T' z"h(ƠEk!M % ՗xjM֮c=֌K>L6H'J/`35P",3zdYi՚P~O(zz;Wz</G$Fh'xj!^$:L|[qbc8pVj2td)u7,cosY\;"5,[\7cĕo^r9)ЙJ~hCf#h\ *q[^#eL4 ABs>H5p2ʋ_Szdet$YmIO"?CJnIO&wt4!al-QY2}d;6Mq`8O  IGAdv _]Ϥz$\,h73d} rSz3'ݲ>G_ BgA[8@W%-$W JL3tq͊Mͷų|v*vu?Z`" 0,CcjT̲ QSeh߮}jwKWϳޠ֩кui݈*Њ]6l~%K!2B [Xn{4TIxZ;eW GFq=(T{0623\`T4l.X!]b$UYQ!";l%(z-[Վl3З KrNGAxcAYkmk!tw ř9\@St2)ЩQ"o99O^_RKbSېMcfeiʈ*KݡTطlhHŽ"XNpGo_mDoℭ5oq)JjYP{)R-}y9>/ YtTLy4MSx6yU0!~Ƙ|Oe0^7X:h% q'҃HgxN {K>+qkq a=cadabra-1.39/osx/XCadabra.app/000077500000000000000000000000001234107666300160705ustar00rootroot00000000000000cadabra-1.39/osx/XCadabra.app/Contents/000077500000000000000000000000001234107666300176655ustar00rootroot00000000000000cadabra-1.39/osx/XCadabra.app/Contents/Info.plist000066400000000000000000000013411234107666300216340ustar00rootroot00000000000000 CFBundleGetInfoString XCadabra CFBundleExecutable launch CFBundleIdentifier com.phi-sci.cadabra CFBundleName xcadabra CFBundleIconFile cadabra.icns CFBundleShortVersionString 1.50 CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType APPL IFMajorVersion 1 cadabra-1.39/osx/XCadabra.app/Contents/MacOS/000077500000000000000000000000001234107666300206275ustar00rootroot00000000000000cadabra-1.39/osx/XCadabra.app/Contents/MacOS/launch000077500000000000000000000001001234107666300220160ustar00rootroot00000000000000#!/bin/bash cd "${0%/*}" #./cadabra open -a Terminal ./xcadabra cadabra-1.39/osx/XCadabra.app/Contents/Resources/000077500000000000000000000000001234107666300216375ustar00rootroot00000000000000cadabra-1.39/osx/XCadabra.app/Contents/Resources/cadabra.icns000066400000000000000000010461621234107666300241040ustar00rootroot00000000000000icnsLris32!+ (%! *6 51-)&! *6 3/,($*6 1/*&$*6 40-)&  *6-&*$# *60"%! *40/,! *#1/*$*/0,($  *2/+&*(-)  *1    +1.*+&"  (0,($  "  ^~ |vtnid^XP(| B| >| 9| 4|~1|IpW6+|.D#|Ihz|EK5! |o0Cj(|Cvx?#W9,|Wce}\HK@0|+r:0G"z3Qkgb]VOKC<2 ) '$  )6 51-)&!)6 3/,($)6 1/*&$)6 40-)& )6-&*$# )60"%! )40/,! )#1/*$)/0,($  )2/+&)(-)  )1    )1.*&"   '0,($   s8mkƹyƴ}kYhоvdRcɷo]K^°ygUCY;r`N;:631.,( T!TTTTTTTTTToZfoT5*dxf1nE>Tfj'd TZ~] TwSy= T}: TkOYT74(q7@TNe;v/6Tce=&A'T"Un/~ TR=1+Ud7:?UTL9N}T;S9L/Td96Fv'4''wfT84i5 T":$C-S~wBPRtQ Z>!GEDB?>;8542.,)($"  6531/-,*(&$# 642//-+)&%#"65310.,*(&#"6531/-+)'%$! 6420.,*('$# 6531.-+)(&$#  642//-+)&%#" 65310.,*(&#" 6431/-,*(%#!  6420.,*('$#  650"()($#  6/ $#  6""10.,* " 6)31/-,*!!  66(420/,*($!  65431.-+)(#   6$420.-+)'&!  68+310.,*(&$"  6 331/-,*(%#!   6410/,*(&#! 6 31.-+)(%    6/0.-+)'#  61/-,*("    64*&,& "  641/%$!   531/-+)'%$!     420.-+)'&#  31/-,*(&$"  2//-+)&%#" 10/,*(&%$!    l8mk¾Ǿ~ulcZQú{ri`WNȿwne\SJż|sjaXOFypg^ULCƽ~ulcZQH?úzqh_VMD;ȿwne\SJA8Ļ|sjaXOF=4xof]TKB90~ƽë~ulcZQH?6-}קzqh_VMD;2)z¤wnd[RI@7.%y|sjaXOF=4+"x쥜xof]TKB90'vƽ֢~ulcZPG>5,#s¹zqh_VMD;2) rǾ̺q[RI@7Xpx$qĻxlXOF<]!4oof]TKBR';mƽDz}ܯbYPGA,#l¹Ҟ~VMDk]IмlǾاڜmͺRI@1%=lۭriNE<*!slîʵofKB>'Alżkc_G>e#ll¹}ğLC:Zf}lǾvmk`RI@7%#lú{ri`WNE<9!lwne\SJA8AF lÿ~zwwwwih32     654310/-,,*((&$#" 65321/.-,**('%$#! 6 54310/.-+*)'&&$" 6 54210/-,+)(&&##!6 431/./-+*)(&%$$" 6!54310/-,,*((&$#" 64321/.-,**('%$#! 6"54310/.-+*)'&&$"  6"53210.-,+)('%##! 6"431/./-+*)(&%$$"  6#54310/-,,*(&&%##! 64321/.-,**('%$#! 6$54310/.-+*)'&&$"  6$53210.-,+)('%##! 6$431/./-+*)(&%$$"   6%54210/-,+)(&&%##! 641"(**( $#! 6&. ("#"  6(5 '10.-,+ #! 6)2 21/./-+*'$$"   6*24210/-,+)( ##!  65 4321/.-,**(#!  6+14310/-,,*(("  6,.53210.-,+)('#!  61431/..-+*)'& "    66154210/-,+)(&&%##!  66 #4321/.-,**('%$#"  7 66-4310/-,,*((&$#"   ,66 53210.-,+)('%##!   ,66 4310/.-+*)'&&     +66 4210/-,+)(&&%!   +66 32/./-+*)(&%"     (66#110/-,,*((&$    665 10.-,+)('%!   *665&,/.-+*)'& "    )6654&-,+)(##!   )66431%  $$"    (654310/)&&$#"   65321/.-,**('%$#!  #54310/.-+*)'&&$"    &54210/-,+)('%##!  '431/./-+*)(&%$$"   &4310/-,,*((&$#"   321/.-,**('%$#!  %310/.-+*)'&&$"  %210.-,+)('%##!     210.-,,)(''&%$#"... . . . . ." ." ." . . .$ .$.$..%jQ?9N~^.&:OdkQO\.(Lz0D.)'F . O?3. '4dW.H $u.,Tq.94R.3,.ah%T'*82,~xrlf`ZTNHB<60*ľɬ|vpjd^XRLF@:4.(ǩysmga[UOIC=71+%}wqke_YSMGA;5/)#񫥟ztnhb\VPJD>82,& ܨ~xrlf`ZTNHB<60*$ľǦ|vpjd^WQKE?93-'!ysmga[UOIC=71+%ſ򧡛}wqke_YSMGA;5/)"¼Ȥztnhb\VPJD>82,& ~xrlf`ZTNHB<60*$ľž}c]WQKE?934fvFa[UOIC=9iP ſŸwqst^XRLF@=j("'G¼vnhb\VPJD>x,& 1l嫜lf`ZTNHBV/)#m6ý㟙{c]WQKE?Y-'!٨㱝|[UOIC=1+Ѵſ̠qXRLF@I.(m|¼פtniVPJD>v,& ШqkeUMGA;J)#㺫uoicQKE?9-'!4ѽsmgaOIC8 }wְɳXMGA;5)x{ý{uoiteWQKE?9?'!.' ~xrlf`ZTNHB<6n}$ ľ|vpjd^XRLF@:4F" ¼ztnhb\VPIC=71% ſ}wqke_YSMGA;5/)# it32J   654332100././-,+,+*)*)(0'&&%&%$##$#!  6-5544332211/00//..--,,++**))(('&'&%%$#$##"!"  65544332100//./-,,++**))(1'&&%&%$##$"! ! 6554432100./..--,,+,**)*('&&%$#$##"#!  6 5544332211/0/- ,,++**))(('&%,$$#$"!"! 654332100././-,+,+*)*)(2'&&%&#$##"#!  6K5544332211/00//..--,,++**))(('&'&%%$#$##"!"  65544332100//./-,+*)(3'&&%&%$##$"! ! 6554432100./..--,,+,**)*('&&%$#$##"#"  655443321/0/- ,,++**))(('&%.$$#$"!"! 654332100././-,+,+*)*)(4'&&%&#$##"#!  6"5544332211/00//..--,,++**))(('&'&%%$%##"!"  65544332100//./-,+*)(2'&&%&%$##$"! ! 6554432100./..--,,++**))(&'&&%$#$##"#"    655443321/0/- ,,++**))(('&%4$$#$"! !  654332100./..-,+,+*)*)(:'&&%&#$##"#!   6"5544332211/00//..--,,++**))(('&'&%%$%##"!"    654332100//./-,+*)(2'&&%&%$##$#! !  655443211/00./..--,,++**))(&'&&%$#$##"#"    655443321/0/-=,,++**))((''&&%&%$$#$"! !  6554432100./..-,+,+*)*)(<'&&%&#$##"#!   65544332211/00//.-,,++**))(('&'&%%$%##"!"    654332100//./-,+*)(='&&%&%$##$#! !  65544332211/00./..--,,++**))(&'&&%$#$##"#"   655443321/0/-=,,++**))((''&&%&%$$#$"! !   6554432100./..-,+,+*)*)(>'&&%$#$##"#!    6 5544332211/0/.-,,++**))(('&'&%%$%##"!"   654332100//./-,+,+*)*)(?'&&%&%$##$#! !   65544332211/00./..--,,++**))(&'&%%$#$##"!"   65544332100//./-=,,++**))((''&&%&%$$#$"! !   6554432100./..-,+,**)*(*'&&%$#$##"#!    6 5544332211/0/.-,,++**))(('&'&%%$%#$"!"!  654332100././-,+,+*)*)(A'&&%&%$##$#! !   6-5544332211/00./..--,,++**))(('&'&%%$#$##"!"     65544332100//./-=,,++**))((''&&%&%$$#$"! !   6554432100./..--,,+,**)*(*'&&%$#$##"#!    6 5544332211/0/.- ,,++**))(('&%=$$#$"!"!  654332100././-,+,+*)*)(C'&&%&%$##$#!    6-5544332211/00//..--,,++**))(('&'&%%$#$##"!"     65544332100//./-,,++**))(2'&&%&%$##$"! !  6554432100./..--,,+,**)*('&&%$#$##"#!      6 5544332211/0/- ,,++**))(('&%?$$#$"!"!  654332100././-,+,+*)*)(E'&&%&#$##"#!    6K5544332211/00//..--,,++**))(('&'&%%$#$##"!"   655443320&  +,+*)(2'%&%$##$"! !  655443,  ,**)*(' $#$##"#"     6552   O %*))(('&%$$#$"!"!  62!+././--( *)(C #$##"#!    65%1/00//..--,,+(('$%##"!"   6, +100//./-,+%(. %$##$"! !   65 (32100./..--,,++**$  #$##"#"     612321/0/- ,,++**)1$$#$"! !    6*&4332100./..-,+,+*)*)A#$##"#!     6$-4332211/00//..--,,++**))(&( $$##"!"    6#.44332100//./-,+*)(( A$##$#! !    6#-443211/00./..--,,++**))( $##"#"      6')5443321/0/- ,,++**))(('%-$$#$"! !   6+54432100./..-,+,+*)*)('B $##"#!     63 5544332211/0/.- ,,++**))(('&' '$##"!"    6154332100//./-,+*)('&B##$#! !    6!5544332211/00./..--,,++**))(&'&$##"#"      615443321/0//./-=,,++**))((''&& $#$"! !   6$554432100./..-,+,+*)*)(F'&&##"#!     6' 65544332211/0/.-8,,++**))(('&'&%##"!"    6 !654332100//./-,+,+*)*)(F'&&%##$#! !    6&45544332211/00./..--,,++**))(&'&%% ##"!"     6 65544332100//./-=,,++**))((''&&%&  #$"! !   6,.554432100./..--,,+,**)*(*'&&%$#$##"#!     6 65544332211/0/.- ,,++**))(('&'&%'$$#$"!"!   65654332100././-,+,+*)*)(F'&&%&%$##$#! !    6(.-5544332211/00./..--,,++**))(('&'&%%$#$##"!"     665544332100//./-=,,++**))((''&&%&%$##$"! !   6 554432100./..--,,+,**)*('&&%$#$##"#!    64 !5544332211/0/.- ,,++**))(('&%$$#$"!"!   6+,54332100././-,+,+*)*)(!'&&%&%$##"#!      6".4544332211/00//..--,,++**))(('&'&%%$#$##"!"     6 5544332100//./-,,++*)(2'&&%&%$##$"! !     654432100./..--,,+,**)*('&&%$#$##"#"      6 544332211/0/- ,,++**))(('&%:$$#$"!"!    64332100././-,+,+*)*)(F'&&%&#$"#!     6J!44332211/00//..--,,++**))(('&'&%%$#$"!"     6#44332100//./-,+*)('&&%&%$"! !    6"432100./..--,,+,**)*(&'&&%$#$ #"       6%!43321/0/- ,,++**))(('&%$ !"!  $    6/4332100./..-,+,+*)*)('&&%&#$ #!  #   6:332211/00//..--,,++**))(('&'&%%$$"!"     6 332100//./-,+*)('&&%&%$ "! !     6)232100./..--,,++**))(&'&&%$##"    6$21/0/- ,,++**))(('&%&%""! !    6 2100./..-,+,+*)*)(#'&&%&# "#!     63<-11/00//..--,,++**))(('&'&%%$ !"!"     65%1100//./-,+*)('&&%& $#! !      6554!/00./..--,,++**))(&'&&$ #"#"      65542 '0/-1,,++**))((''&&#$"! !    655443/&./..-,+,+*)*)('&##"#!      6554433- /.-#,,++**))(('& "$##"!"     654332/-, +*)*)(( %$##$#! !     6 5544332211 (++**(" $$#$##"!"      6554433210/"%&%$$#$"! !     6554432100..  '&&%$#$##"#!       6 5544332211/0/.--%"('&'&%%$##"!"!     654332100././-,+,+*)*)('&&%&%$##$#! !       6-5544332211/00./..--,,++**))(('&'&%%$#$##"!"       65544332100//./-%,,++**))((''&&%&%$$#$"! !    66554432100./..--,,+,**)*()'&&%$#$##"#!       665544332211/0/.- ,,++**))(('&%$$#$"!"! '  6654332100././-,+,+*)*)(F'&&%&%$##$#! !    /65544332211/00./..--,,++**))(('&'&%%$#$##"!"    65544332100//./-=,,++**))((''&&%&%$##$"! !     554432100./..--,,+,**)*("'&&%$#$##"#!       5544332211/0/.- ,,++**))(('&%:$$#$"!"!     54332100././-,+,+*)*)(F'&&%&#$##"#!     -544332211/00//..--,,++**))(('&'&%%$#$##"!"    544332100//./-,,++*)(2'&&%&%$##$"! !   4432100./..--,,+,**)*('&&%$#$##"#"       44332211/0/- ,,++**))(('&%:$$#$"!"!   44332100././-,+,+*)*)(F'&&%&#$##"#!     I4332211/00//..--,,++**))(('&'&%%$#$##"!"    4332100//./-,+*)(2'&&%&%$##$"! !   32100./..--,,+,**)*(&'&&%$#$##"#"      3321/0/- ,,++**))(('&%@$$#$"!"!   332100./..-,+,+*)*)(F'&&%&#$##"#!     32211/00//..--,,++**))(('&'&%%$%##"!"    32100//./-,+*)(2'&&%&%$##$"! !     66554544322121100/..-.--,,++*)**)((''&&%%$$##"#!"!!   22 222 22 22 2 22  2 2  2 2 2  2 2  2 2  2   2 2  2 2  2  2 2 2  2 2   2 2  2  2 2  22 222 2  2 2~^A6-&,9Hm:J2X(-s302`"!,.!'CU 2MBnY# oS 2Z 3z_ fd 26 tp,2Q|v P2)Jx{ 2} u@  2l+ 2i/M2j hv2v| 2\& 20 /G 27 9r2cX B2 K$ 2/mGF 2u @m 2"d8 2r /)2$La 22A   2 S2w 2H V )Dq?&U29 $ * 0 $2b 1#VjU&_ 95>12~#{+z^ = 2e LDv&> _ U 72S:)]*2J4 Dc#;2@H]( 2:YaOY 2@d  Jm2Hj`T 32Zk +B-= +2peJ= <2Y9& Kt/&2CqZ\*y2B ( 3(J :y! -2z m6#yh2u M V g4VP 4  t2_:'$/J %2 6![Av7uMKv2q; 7 { 'J 7vw2@l 0 xB+,S 2"  wrc $2 |R  8  62W o0 gs2<cb$a(!  R 2lBfZ2 AH %f2U  Bl522l9 0^ M bj2dN@@?ENh@W2G'P# &2V+ %d[2 ~$ 2 ;d \]2  Pr~)% t2*M'Q2*( f/]2| 6`eF![8 (1& "2 JL(|2 ~M95Ck*W$ $2e1 ^1&1(0 d0 _0  '0&/ j0 A600 0  )('&&%%$%$##""!     654332100././-,+,+*)*)(4'&&%&%$##$#!  6-5544332211/00//..--,,++**))(('&'&%%$#$##"!"  65544332100//./-,,++**))(5'&&%&%$##$"! ! 6554432100./..--,,+,**)*('&&%$#$##"#!  6 5544332211/0/- ,,++**))(('&%0$$#$"!"! 654332100././-,+,+*)*)(6'&&%&#$##"#!  6K5544332211/00//..--,,++**))(('&'&%%$#$##"!"  65544332100//./-,+*)(7'&&%&%$##$"! ! 6554432100./..--,,+,**)*('&&%$#$##"#"   655443321/0/- ,,++**))(('&%2$$#$"!"! 654332100././-,+,+*)*)(8'&&%&#$##"#!  6"5544332211/00//..--,,++**))(('&'&%%$%##"!"  65544332100//./-,+*)(2'&&%&%$##$"! ! 6554432100./..--,,++**))(&'&&%$#$##"#"    655443321/0/- ,,++**))(('&%4$$#$"! !  654332100./..-,+,+*)*)(:'&&%&#$##"#!   6"5544332211/00//..--,,++**))(('&'&%%$%##"!"    654332100//./-,+*)(2'&&%&%$##$#! !  655443211/00./..--,,++**))(&'&&%$#$##"#"    655443321/0/-=,,++**))((''&&%&%$$#$"! !  6554432100./..-,+,+*)*)(<'&&%&#$##"#!   65544332211/00//.-,,++**))(('&'&%%$%##"!"    654332100//./-,+*)(='&&%&%$##$#! !  65544332211/00./..--,,++**))(&'&&%$#$##"#"   655443321/0/-=,,++**))((''&&%&%$$#$"! !   6554432100./..-,+,+*)*)(>'&&%$#$##"#!    6 5544332211/0/.-,,++**))(('&'&%%$%##"!"   654332100//./-,+,+*)*)(?'&&%&%$##$#! !   65544332211/00./..--,,++**))(&'&%%$#$##"!"   65544332100//./-=,,++**))((''&&%&%$$#$"! !   6554432100./..-,+,**)*(*'&&%$#$##"#!    6 5544332211/0/.-,,++**))(('&'&%%$%#$"!"!  654332100././-,+,+*)*)(A'&&%&%$##$#! !   6-5544332211/00./..--,,++**))(('&'&%%$#$##"!"     65544332100//./-=,,++**))((''&&%&%$$#$"! !   6554432100./..--,,+,**)*(*'&&%$#$##"#!    6 5544332211/0/.- ,,++**))(('&%9$$#$"!"!  654332100././-,+,+*)*)(?'&&%&%$##$#!    6-5544332211/00//..--,,++**))(('&'&%%$#$##"!"     65544332100//./-,,++**))(2'&&%&%$##$"! !   6554432100./..--,,+,**)*('&&%$#$##"#!      6 5544332211/0/- ,,++**))(('&%;$$#$"!"!  654332100././-,+,+*)*)(A'&&%&#$##"#!    6K5544332211/00//..--,,++**))(('&'&%%$#$##"!"   655443320&  +,+*)(2'%&%$##$"! !   655443,  ,**)*(' $#$##"#"      6552   K %*))(('&%$$#$"!"!  62!+././--( *)(? #$##"#!    65%1/00//..--,,+(('$%##"!"   6, +100//./-,+%(. %$##$"! !  65 (32100./..--,,++**$  #$##"#"      612321/0/- ,,++**)1$$#$"! !   6*&4332100./..-,+,+*)*)A#$##"#!     6$-4332211/00//..--,,++**))(&( $$##"!"    6#.44332100//./-,+*)(( A$##$#! !    6#-443211/00./..--,,++**))( $##"#"      6')5443321/0/- ,,++**))(('%-$$#$"! !   6+54432100./..-,+,+*)*)('A $##"#!     63 5544332211/0/.- ,,++**))(('&' '$##"!"    6154332100//./-,+*)('&@##$#! !    6!5544332211/00./..--,,++**))(&'&$##"#"      615443321/0//./-=,,++**))((''&& $#$"! !   6$554432100./..-,+,+*)*)(F'&&##"#!     6' 65544332211/0/.-8,,++**))(('&'&%##"!"    6 !654332100//./-,+,+*)*)(F'&&%##$#! !    6&45544332211/00./..--,,++**))(&'&%% ##"!"     6 65544332100//./-=,,++**))((''&&%&  #$"! !   6,.554432100./..--,,+,**)*(*'&&%$#$##"#!     6 65544332211/0/.- ,,++**))(('&'&%'$$#$"!"!   65654332100././-,+,+*)*)(F'&&%&%$##$#! !    6(.-5544332211/00./..--,,++**))(('&'&%%$#$##"!"     665544332100//./-=,,++**))((''&&%&%$##$"! !   6 554432100./..--,,+,**)*('&&%$#$##"#!    64 !5544332211/0/.- ,,++**))(('&%$$#$"!"!   6+,54332100././-,+,+*)*)(!'&&%&%$##"#!      6".4544332211/00//..--,,++**))(('&'&%%$#$##"!"     6 5544332100//./-,,++*)(2'&&%&%$##$"! !     654432100./..--,,+,**)*('&&%$#$##"#"      6 544332211/0/- ,,++**))(('&%:$$#$"!"!    64332100././-,+,+*)*)(F'&&%&#$"#!     6J!44332211/00//..--,,++**))(('&'&%%$#$"!"     6#44332100//./-,+*)('&&%&%$"! !    6"432100./..--,,+,**)*(&'&&%$#$ #"       6%!43321/0/- ,,++**))(('&%$ !"!  $    6/4332100./..-,+,+*)*)('&&%&#$ #!  #   6:332211/00//..--,,++**))(('&'&%%$$"!"     6 332100//./-,+*)('&&%&%$ "! !     6)232100./..--,,++**))(&'&&%$##"    6$21/0/- ,,++**))(('&%&%""! !    6 2100./..-,+,+*)*)(#'&&%&# "#!     63<-11/00//..--,,++**))(('&'&%%$ !"!"     65%1100//./-,+*)('&&%& $#! !      6554!/00./..--,,++**))(&'&&$ #"#"      65542 '0/-1,,++**))((''&&#$"! !    655443/&./..-,+,+*)*)('&##"#!      6554433- /.-#,,++**))(('& "$##"!"     654332/-, +*)*)(( %$##$#! !     6 5544332211 (++**(" $$#$##"!"      6554433210/"%&%$$#$"! !     6554432100..  '&&%$#$##"#!       6 5544332211/0/.--%"('&'&%%$##"!"!     654332100././-,+,+*)*)('&&%&%$##$#! !       6-5544332211/00./..--,,++**))(('&'&%%$#$##"!"       65544332100//./-%,,++**))((''&&%&%$$#$"! !    66554432100./..--,,+,**)*()'&&%$#$##"#!       665544332211/0/.- ,,++**))(('&%$$#$"!"! '  6654332100././-,+,+*)*)(F'&&%&%$##$#! !    /65544332211/00./..--,,++**))(('&'&%%$#$##"!"    65544332100//./-=,,++**))((''&&%&%$##$"! !     554432100./..--,,+,**)*("'&&%$#$##"#!       5544332211/0/.- ,,++**))(('&%:$$#$"!"!     54332100././-,+,+*)*)(F'&&%&#$##"#!     -544332211/00//..--,,++**))(('&'&%%$#$##"!"    544332100//./-,,++*)(2'&&%&%$##$"! !   4432100./..--,,+,**)*('&&%$#$##"#"      44332211/0/- ,,++**))(('&%:$$#$"!"!   44332100././-,+,+*)*)(F'&&%&#$##"#!     I4332211/00//..--,,++**))(('&'&%%$#$##"!"    4332100//./-,+*)(2'&&%&%$##$"! !   32100./..--,,+,**)*(&'&&%$#$##"#"      3321/0/- ,,++**))(('&%@$$#$"!"!   332100./..-,+,+*)*)(F'&&%&#$##"#!     32211/00//..--,,++**))(('&'&%%$%##"!"    32100//./-,+*)(2'&&%&%$##$"! !    t8mk@~|zwusqnljheca_\ZXVSQOM}{yvtrpmkigdb`^[YWURPNL|zxvsqomjhfda_][XVTQOMK~{ywurpnligec`^\ZWUSQNLJ}{xvtqomkhfdb_][YVTRPMKI~|zwusqnljheca_\ZXVSQOLJH}{yvtrpmkigdb`^[YWURPNLIG|zxvsqoljhfca_]ZXVTQOMKHF~{ywurpnligec`^\ZWUSQNLJGE}zxvtqomkhfdb_][YVTRPMKIGD¿~|zwusqnljgeca^\ZXUSQOLJHFC}{yvtrpmkigdb`^[YWURPNLIGEB~|zxusqoljhfca_]ZXVTQOMKHFDB~{ywurpnligeb`^\YWUSPNLJGECA}zxvtqomkhfdb_][YVTRPMKIGDB@¿~|ywuspnljgeca^\ZXUSQOLJHFCA?}{yvtrpmkigdb`][YWTRPNKIGEB@>~|zxusqoljhfca_]ZXVTQOMKHFDB?=}{ywtrpnkigeb`^\YWUSPNLJGECA><}zxvtqomkhfdb_][XVTROMKIFDB@=;¿~|ywuspnljgeca^\ZXUSQOLJHFCA?=:}{xvtromkifdb`][YWTRPNKIGEB@><9~|zxusqoljhfca_]ZXVSQOMJHFDA?=;8}{ywtrpnkigeb`^\YWUSPNLJGECA><:8}zxvsqomjhfda_][XVTROMKIFDB@=;97¿~|ywuspnljgeca^\ZXUSQNLJHECA?<:86}{xvtromkifdb`][YWTRPNKIGEB@><975~|zxusqnljheca_\ZXVSQOMJHFDA?=;864}{ywtrpnkigeb`^\YWUSPNLIGEC@><:753|zxvsqomjhfda_][XVTROMKIFDB@=;9742~|ywuspnligec`^\ZWUSQNLJHECA?<:8631}{xvtromkifdb`][YWTRPNKIGDB@>;97520~|zwusqnljheca_\ZXVSQOMJHFDA?=;8642/}{ywtrpnkigdb`^[YWURPNLIGEC@><:7531.|zxvsqomjhfda_][XVTROMKIFDB?=;96420-~{ywurpnligec`^\ZWUSQNLJHECA?<:8631/-}{xvtromkifdb_][YVTRPMKIGDB@>;97520.,~|zwusqnljheca_\ZXVSQOMJHFDA?=:8641/-+}{yvtrpmkigdb`^[YWURPNLIGEC@><:7531.,*|zxvsqomjhfda_]ZXVTQOMKHFDB?=;96420-+)~{ywurpnligec`^\ZWUSQNLJHECA?<:8531/,*(}zxvtqomkhfdb_][YVTRPMKIGDB@>;97520.,)'~|zwusqnljheca_\ZXUSQOLJHFCA?=:8641/-+(&}{yvtrpmkigdb`^[YWURPNLIGEC@><:7530.,*'%Ӱ|zxvsqoljhfca_]ZXVTQOMKHFDB?=;96420-+)'$௭~{ywurpnligec`^\ZWUSPNLJGECA><:8531/,*(&#ͮ}zxvtqomkhfdb_][YVTRPMKIGDB@>;97520.+)'%"¿~|zwuspnljgeca^\ZXUSQOLJHFCA?=:8641/-+(&$"}{yvtrpmkigdb`^[YWURPNKIGEB@><97530.,*'%#!̾ᮬ~|zxusqoljhfca_]ZXVTQOMKHFDB?=;96420-+)&$" ͭ~{ywurpnligeb`^\YWUSPNLJGECA><:8531/,*(&#!}zxvtqomkhfdb_][YVTRPMKIGDB@=;97420.+)'%" ~|ywuspnljgeca^\ZXUSQOLJHFCA?=:8641/-+(&$!⬪}{yvtrpmkigdb`][YWTRPNKIGEB@><97530.,*'%#!ά~|zxusqoljhfca_]ZXVTQOMKHFDA?=;8642/-+)&$" }{ywtrpnkigeb`^\YWUSPNLJGECA><:8531/,*(&#!}zxvtqomkhfdb_][XVTROMKIFDB@=;97420.+)'%" ¿䫩~|ywuspnljgeca^\ZXUSQOLJHFCA?=:8631/-*(&$!Ϫ}{xvtromkifdb`][YWTRPNKIGEB@><97530.,*'%#!~|zxusqoljhfca_]ZXVSQOMJHFDA?=;8642/-+)&$" }{ywtrpnkigeb`^\YWUSPNLJGECA><:8531.,*(%#!媧}zxvsqomjhfda_][XVTROMKIFDB@=;97420.+)'%" ¿Щ~|ywuspnljgeca^\ZXUSQNLJHECA?<:8631/-*(&$!}{xvtromkifdb`][YWTRPNKIGEB@><97530.,)'%# ~|zxusqnljheca_\ZXVSQOMJHFDA?=;8642/-+)&$" ਦ}{ywtrpnkigeb`^\YWUSPNLIGEC@><:7531.,*(%#!²|zxvsqomjhfda_][XVTROMKIFDB@=;97420.+)'$" ~|ywuspnligec`^\ZWUSQNLJHECA?<:8631/-*(&$!}{xvtromkifdb`][YWTRPNKIGDB@>;97520.,)'%# ~|zwusqnljheca_\ZXVSQOMJHFDA?=;8642/-+)&$" }{ywtrpnkigdb`^[YWURPNLIGEC@><:7531.,*(%#! ּ|jhfda_][XVTROMKIFDB?=;96420-+*E^vu`' fc`^\ZWUSQNLJHECA?<:8631/_? ͝|b_][YVTRPMKIGDB@>;9752YuH>Cm ~|zwu|ma_\ZXVSQOMJHFDA?=:8666&$"2` }{yvtrpyb`^[YWURPNLIGEC@><:7F?*(%#!u |zxvsqomjhfda_]ZXVTQOMKHFDB?=;9G-+)'$" 7v ywurpnligec`^\ZWUSQNLJHECA?<:H{/,*(&#!'xvtqomkhfdb_][YVTRPMKIGDB@>;;0.,)'%# A¿Ǥusqnljheca_\ZXUSQOLJHFCA?=:1/-+(&$"a{rpmkigdb`^[YWURPNLIGEC@>;]20.+)'%" ¿ࢠ~|zxgeca^\ZXUSQOLJHFCA?=B41/-+(&$"+}{yvdb`^[YWURPNKIGEB@><:71/,*17ȣ͆o|][YVTRPMKIFDB@=;S20.+)N ¿⤢spnn\ZXUSQOLJHFCA?=:1/-+('h画trpmkfYWTRPNKIGEB@><9a0.,*'%#!#+)WXusqoljiXVTQOMKHFDA?=;86/-+)&$"  wtrpnkigWUSPNLJGECA><:P1/,*(&#! XvtqomkhfyVTROMKIFDB@=;90.+)'%"  ¿ﴩwuspnljgecUSQOLJHFCA?<:8^/-*(&$! ߯vtromkifdbTRPNKIGEB@><975.,*'%#! ƮxusqoljhfcaSQOMJHFDA?=;8N/-+)&$"  سwtrpnkigeb`SPNLJGECA><:7}.,*(%#! ڹvsqomjhfda_ROMKIFDB@=;97a.+)'%"  7йwuspnljgeca^hQNLJHECA?<:86:-*(&$! |BȾvtromkifdb`^RPNKIGEB@><97I.,)'%#  usqnljheca_QOMJHFDA?=;86z-+)&$"  2rtrpnkigeb`^fPNLIGEC@><:75;*(%#! sqomjhfda__ROMKIFDB@=;974t)'$"  4=~rpnligec`^fQNLJHECA?<:86E(&$! h}omkifdb`cRPMKIGDB@>;975vv%#  ~|znljheca_TQOMJHFDA?=;864hB[" t}{y}ligdbaYRPNLIGEC@><:7537*W)DF|zxv{}yXTROMKHFDB?=;964C+)'I_@46l~{ywurpЀWUSQNLJHECA?<:863s*(&##kԁ}{xvtromkon[YVTRPMKIGDB@>;9752h)'%# #FfqpR# ~|zwusqnljheca_\ZXVSQOMJHFCA?=:86415(&$" }{yvtrpmkigdb`^[YWURPNLIGEC@><:753A*(%#! |zxvsqomjhfda_]ZXVTQOMKHFDB?=;9642s)'$"  ~{ywurpnligec`^\ZWUSQNLJHECA><:8531e(&#! }zxvtqomkhfdb_][YVTRPMKIGDB@>;975203'%#  ¿~|zwusqnljheca_\ZXUSQOLJHFCA?=:8641>(&$" }{yvtrpmkigdb`^[YWURPNLIGEC@><:7530o'%#! |zxusqoljhfca_]ZXVTQOMKHFDB?=;96420f'$"  ~{ywurpnligec`^\ZWUSPNLJGECA><:8531/0&#! }zxvtqomkhfdb_][YVTRPMKIGDB@>;97520.JQ'%"  ¿~|zwuspnljgeca^\ZXUSQOLJHFCA?=:8641/-+(&$" }{yvtrpmkigdb`^[YWURPNKIGEB@><97530.,*'%#! ~|zxusqoljhfca_]ZXVTQOMKHFDB?=;96420-+)&$"  ic08 jP ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cOQ2d#Creator: JasPer Version 1.900.1R \@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP]@@HHPHHPHHPHHPHHP i߁b[׻TQvF-5Mx]a i;*I:7&ָ&?gGϴ+m,K7KqUI>:X#D坮7=W0bGdn֖_߁b[ÊZ|u6&/uR7WBNv2y}߂rAsC(V_ CҵuhY= Y=2u.1nQPV$c)O;vJx(ѧ.x^}@i ;b4T; dtpb= M|4v{QQS/[ЊpK ]p;q v,&oy->y;vB|B -B>E{\%IAS:QvbBvru!ܣ w1ʫZS.b۠%٠(ҋ]aOatMΠ$lͲ(<]<%D9̍<m%qW{fWΖiP;|KO+-W66^r|,_ !<x?/s"Lװ^ӣ9 tʂ$LP9(tqg*[ЊpK ]p݅)_NuU>Ҹ Q"MչI,ZK"m$]*;6B"v32 EC_Y6,%`֤*C,"rB P XdV53Y5 k#I T%NDDs;-^U 2E+Jq:v ]xOhG1; $ˈ2ɠe&8Ouh:84TԘC[)R&}"YSZ=7u%OY0_Hasʌ ھI`tFD;h|v7V=w~6k.!{L;;0¶K?:-b?dB0֊Bd Q:Ubp%~U{_4vh(:ܸf9(m_@Co ʳ(>j&J 9y5N$&aIS'vJC7*%HϤJla?~шn vǦq I2ÖGz߉3 n{>mzi s} f54%ڛ}H;. wHIxsa_%}Ɵ6Ѥ!#HfV>gXN`v扞ZlBocsʉJ<_uh:84TԘC[)R&}"b"r)E[P{^mf6XWwY)%EP`C|NN,D/ӛuKVߝ#? ~thJ_н+q2;:3iSI8ŐKUǢߕ@H{sׇRBZo^ˁƺn@X΂{=OҨ}úGLM~M;ܑhzKSʯǼmܿ:=o¶HHA 83AnEE<ԫ}Vxl &#fKڻ!EL1 UܣY"h`P/|@ѓG0NT>BudhpN 42߽k`pS{^Ȗ#a!S҉*)CR q78) =: i_^'4kǕWR(l_q/w8 r1= m?o}}Z[$Q@$lLy!ֱv-qE lNSS҉X=s݅s ޝ^\;֏O-F^,q;og:K &q"6 =H=%cPsc)5 @0{ 0zpsG1Omn{wpMHb.;/D=`]Y&v,1@]9Uۧ9ptXG'eNgbe9bJ^'Od;G{9LU'[އ?K`z1S;}ȥg *=N͞uM/b߯y^"oaRۉY?_.EUIVƓ0IP])qaR:(3/y~JXjHo!oY e9N~ ]rƱ^7FVk]"I#VOEȰIRQw"F┊ &6*k|r*UP[iJaiQBnWȶ7|7x0n2m{>xi9340`+@o,TVTۯ=sǏh0 t#Nply&Ò(u_G<;?'=VVoqh߂.X,T\3&%Rb>[Ugf 8^x{f${er;#~4D|0aġ|LF(`! ܠ3 n?}PhKe vzwpyLjkmt :/ը"Z,=anaXpd6Ő7r#dS '7 q7RQC_ #ẕ|#]lY /n2gpfpR\H`b]BDȿUS&2/Yh&XًcJo}Lͧ:yO:a@6(SMlcL@|%G&. ll;''ySDt/ wj=*Ǘ@~:J̸Ov *ޏsS7ꖃAG5\[y~cDy3á)n~bԸ >Rs_͆W00f=}` X3WPׇm!:FpE&0d"UR" ~@1W娟\,!y3?+Z 10kw࿡*IzLp\znJH@QuxwdN! W|u)Q8{Pi\_i+ΐ@8IAr]wyLCģ} (L?-i]CQ |Z~vPi, FǗ7|H^ݖžs\,gϞ471lp8e6̑^L]* 0E(A}\_ߡ1e 4k_՛4r3,rgDvh& |sX ,8Z!ܜ#ˎ]W'R`!B٩k1=t,J뎃塎oA}%)ON6RDIV|R=H^GÞctkު㫑dVE^\haK^k Ҿ>۸ l׻Jg\3z4G~DWܠu$JێYuz=^3Viaם]+55e4 TjRջ b<@;QZ|#׶GO'h7Wڎ?^bߜ>U4k3$mb inUJԏ;`mFeҶ5;A K |ljSY.eވҽjUŧ"!t(tt:J! YV u 8"9|9Ҍr| |viHo!~;Y*tL6*σ<7S~op^_}=іɏvZ^bu`smqiH Zmqʼr2FzCҒS;c=bfՃ]ļO%Z(\[??y/*;u6C:̑ *|$OcwV_H}Z[~?M>/\wޙytNE7moh@GaQp~3]bvJ)5myG3͊A<2\l=V|9^O`櫿@Y}VUkIPRo!N]~):TG TV(!6z~ *'P`Ӛкo"! jȻl(`.ZZdvΰrʑQ̟SJB=^5,.TJp'o@X"֙].wPE]XNzIPeۯ\~qWcBI&iڣSHm~R AC׻dS9,6Kl3r-bOsf]|DAYmҮ@3aܑ xBk=Qjc)oOW qCMԣgd{um;#^)k!ܛ DUҥ ?' za e- ~l{y&;o6*N͐.-7ZCьf !$p?a]f1Ȣycݪ_l*rͮi θ+mV2Z.ⴠKM*EB8^x{f=޶1KxMƸ-__0aġ|LF(`! ܠ3 d.xUp*OO27\G#yڽ+Fb IE7g' ̇M82N.Ur"닕XpLT˽PHjΨg1dLɘB`ưbf(g< ATXX'行 A1Ä*&w_j0yqcΜP76 `5!Kk5GE'17r,l%yWH!(]&fJ&@xqú Ve`4QŶU|!FY^&N7V]Z.b^5;.^EEx)KAn.1ƉH (ߞߞcb]Cx_FLmu<"4aNS!IUō,rQoSE{2y(c RAl)=$/L)u*Pyi͹nkLw0/{]1oG9X +[T?[O7WVv,"2'̇pPyy/T烮q+FƗ/f=_a썳* PW<<4UQlRzUkvrXl->n|gE-DB_LPM }z)@(Ev/ BFWHw3܃[ 2ncb;!C)(*4wrݩi$7r_vbՔj7γXG oQu+_08ԅ4N2\swmEEa}ߌbpC B9FP5i,13\j1'BY'5{r@!€koyRw8e$1 XDU} ;Ow X ӗͤۨ/*Dž+<%-9Dkn@}l 4t[OBSY|0Y49,šXPzz>F~ޜ\*bfXe;KtU&wMI6cBÁA?Fa /+6 FԨ8ʖIkfQv:z)SQkYROi#K:axN"8ERm+L.])H\͏R"nӮY8صIk=BL\uw)P(ȏs+i]ۇҳq2؇Z?tYxp}z {:-p6lqfRr(/Ԃ9>1 ߷7pE8,1F<2av#t)!re-W^gA=)Pz=HQ:5lBD7{1tB]dW2M!ѽANtɝ0S 3h]_ݯipouHЀ^)mwo9YٻAŲSXW-_`x<$uL "f1Rk4Xs֔l8VᖾlIQK,JP6V? lE"쮋gR\XFw{l0HܖMLђ'~4.*"dWq& agPE_khgJ,?l't>SEg X$ H F"Tz;Nm!Э8_]N<.J2ƷLq܁,PkV 9Oa觽kٲ&:0~vC56S@3?i R4=wiz(nѵט3 5@Q\eR7@SJ<ݾq8H=`N<_VKUYh ˘w5缽o1L f4 m]J S,{; [D+w$0R0]$okNihn.#UH!Bc/'3! W&l j4e=Ά^Yg]4Ym'X:$od~S/(*$AgFڥ%I;0ٗObC \)cN9cb2FM(_A,Halfri`kXZɳx$jMc^+lIj`U`h׍:z0waxA_'|V }:QZ*6S=)ZVq T*,G"C/ys up16fS;e|&$1@9FԊfD 4-%!ʚ3u^rǎߙ^"+Ƥw(iU-{FF!;T>/$,5O{錠PJ%ax Kd৾bvE;rF"JRF\2 `vItxUפsd=fbljY2{8-4mGtơ ski!l LEczFWܗE.|>".&(Ζl h(帗Hxs>iRIPӎH OueR5 ԞZk~5%4CϬCa:UaSJryA>CERyT9cYs\ a 1+YArϨ[@J3/` >1潮zUQ2Y[%@2 [sI[χm`~bC23BYku| Ey Ze8727/ E7]6Z&X\ 5Ǚ_@kdXf=S<:*%Ql㒓1 D Ĵ]'תq<%~:C͘~WvToV}JIG K`b*Rr&YcXJ#A7=r1=~=}4 @<*:tAnRlGj3Qh󸜽^d1-$7+ DIVi:nfBXcDv-+^+?wTr7#ĵ!wh}n]I&餓#uz`^Tr7pkQN=XKҫ6 䀉K]kt[=ܼl.ues)5PG)LɕKHH& cÿܰL~(w,UMX+Xڌ}Duϐ)F`79S'59lh֬N!67uc$[(qψh{x5ӧE'9dǽz=p1cź_顗`RHX"y{ Qf&:_v3^#ı`Z 1J K[tx5R2}Vtmbb]zlqpUwY bSPj9=wf'Y'T{Nŭy(S P@D}UāQB,pt14eMU%^+obt٣kNO#ʀ>z6s B/;ܓ VD}=KqBs RRJ{h\S*xr&}3?RŻ,R/*&ii8NþTͥ H7:_3 8RO]Y.!! g0tJ+&ͦ?M͆P+:W\oinAm!RGd7~gbp(aFluwǚɆ (w+m8VϾ Ո\Erz~gMU5e=)QFCjr}@ P{×v`%ȱ|́1qPmDoWH0n0UI:p/'<(OKPFnRʡpCHs׻-`N aH%5߫Ľ濫AU.^tRUANy$ΕW4qInoP9bcPtE/bo3o &40͙7g,be.!"83~k̕&(5?ׅBX٬R^IxRf}N|>ǤiI#샤Uoq+ ?h=O2=Գ\m_,;tl dW r.Ŝ72gn'o0 E,d<=ضlǀZ^!>wc_Õͤi cL98Bfhc)qU@, 5Q<5R>RH=ie-fs{Jˡʹ2cwK}>F([1@A onF3݀҆Sq.^B"}K:Wbp[ie(4ǕOGat/ 7lm͞U&fzU4'ML<7w_Ul@:G575@w/*piO3Ct~)lERE֥9g )Ά |{"@u粮K(W%_?ݬS Jz^t<_q^i>2Z`ўLVv|\$f?)α=(jSGǦZ~*akЙC1}siVVB{lN/2i"S eؖe<*fƣd\~]q/JQKDڌ{'1_b{.3E_M#Q} F"8 D([!F֪oXquadak㉏0`sLp]+>e>%@ =?FtER*3S} kO'ԂBf`Fj},1 ฑ2udp/ך[dXvU/ר,P ym\IXi7_4zZ`>[K_PU.ᝎu 2#`؈.V j\C:]~0bۻoȇ6&rd6;[s_΅6S{'O?WS0㇤I^ 0(kdKpV:qv`~ns@;x*&7*hw2!iEHn`K1piHco#A;G7Řm H%&u=NjYƓ\Ӛ@P:+c;eKKn\*Veiܨy@ycM7i|I]uGR ү >rB˭55 |Xׇg4< ߽~Z>0Iewnm&mim *d_>3Oܟ?W:A*eeÙ.+"LJhF!צ^-x֯0 7v}1KZcEB2OpM_# <)Ck, :J'o 2l:rr\-`r"\g;܋6<QyC"Ia=7= N`sG4Ga嶴:Ժ)1@$+,-r(E|(!-y$z@>bHޭ,N+ڡ'O7;Jt(QZ`$cF' F>o;-Urs]!|3튲:V@i>?UB2#8έyxiLG$j$aUΎ1srl>UpA4Pߤk7&R%@ܩ#T8i4S5q L*xݴAQ"g<tÆ5{7,u80PHJ_oG" ?4TN"Nb*P{#IyhY)"MxՌbGELCj"zX UU˄?Ƴ3Y,Vv8yHSBH9OiZ-3klo;纵 q&c!ۓrձyX QT63q` @mcY }`Q(GEj0`{rs-p\V)V9t]M%M#VInb)Xr{Fc 2@m76T;UsI͉Vƞe\ߚ@"S]rWƁ,|oygS%^Żi. 8qIR_W6/ $OB< uOO;hv%ik8D=~F.9o| et?xU c~m,2.r vK&-q{5딉^Hthc;ϫ^z+^yawaba*S8;˄[ÎAФ1^hCK!ʫbOR~0=X-'ip! kRUhce4,}cZ;`o!ȸݎյD.q2fr0K }\~G+lZ3bs!ВSEg NJ$e&ύT y_҄f}7̚嵐wJ4u^zq(2$=uLRC'8WE"JlQ\╺ 5gX9#QT<}%-.fK!dLإKT\x*I?rD#jolWܫnZ; fHZ#[}"ߘt.;,☁X#0|+%繽U:ҧU,B3hL,HV5u2sL4R%/dKhkٵ҄ǹ۳>J{VM2'm54`Rʪ$`!1ݓ^}]E9eԽNmԠK=)<XɎD] Tx n6߯uv߶z>4AR%i6KpګqG=[2tktz~z-,ҫHoki[̷jp3gQ N.Uqᬚ"NΩ*{/ZOVң/xRz_#]Ɓux6?FfG9ogq;˓)jH ~E(17H!L3^qSS'lc`dC p|i_d 9^|V/)[S Y)!{7_/{uۗ ^utm"6 %jat6ߣL9%5m ڗ7uq>([dt=4iWM渙=? Gk^L- ꤒ *۴NG5B[YPCER&:3FVTΤ&t.Z'D-h<20˜S-v֞"JjXT2oGܘ.LˊgA]UhGKKr,a;݀d%> BE Dn-\™|>d_tW_;j DJw{$='+3I2Ӧ\kHL$-:8WزdO$n۹xZޱ:"QK\S㚤h5Me h1ub*kդy,P=I:jШ#PKVQʝb*zð@[f1L;˽:؟JhV(#hM:ӄXtA! 9Z ϼq1,C˪ŏqgaW o瓣ž@-xz$=A%_ J`xMErpQ 본@Z3oR_SY7y{XzA-#,tެA4f/FWN9~ReZO2OJ_|UT\ d=qi )-#`k`( 4鵖^b.-cp뫌@ }FTʿ8w0Vp-"1 2@|(Waha~FE fPUk AB5YCoDÚO_K*$hp1w͐XG ZX ^``؞^Ζp0 Ch꿟yMd4~l6}y˲35+B~%9B9i;3/4 fZ1by@nY( IjݘNF@)*_)S5*6̌0㖩&0{B <f^ ܅&mZ`:h2;h"@ 3%eA*U֥k+1MHﻅSaT')JXH|=@TĈabcQ.EV |n֛_ރ~M\_xdYną(5D p6a:(ߖv_:@B{rf%;Pڪ8@~OSxPkw P2gn'o0 E,d-ّͣjCwZA!@0AKP`Ɋ\DK(lE Wgwm5%BPbO@Z.\b7ŮאCH@3aOn JS|JC nrJj LPeQr1)B312I8-ھI#u| 0Ew"b%Ϯn, l\=86Й\8TIb˧Usip)W2HțēM<70PLnpYk>`XhSH- 6r[dI\1[uᓈt%V@O[gGONY槛ѶGH<tJΛnek3:bffɛh{ʥ!fscc*h׫ rͤ"ό\{€R}9 U. ~ֆV [F%$e$aHm2QA=.1Į^z8m''l!w|]\heFk[`ck11ǡ6F7Z Յ[].b-IPB5E/% =Uc3W/$mtq{O'by`}jBua$2f_u%n̮CıZeb+_5ܱCѧSkG>ϒv3WZBq_GZ".KJRgndb&e \%`/RN:Y^# c;f;n֮9O蘦{1mMZswAG\]~egr$2|82KzȰ8gA\yNޟq"Se;WLܽTi8ĄAWմ7`il݋9{ X%q+ol,8SLc/J\pM11G~ƥ$ZQM؅f=@D-i]/)c;{Ra4[|xEҾdU5S YThocMQ؋BY_.4 m[ ~"q(>P]W+ O{ր׎cBڮh?A*R7@][Dx0j 5Fz#LxVǹw^CjTػBc2n4MOXf-d82+l)$e$*!}γ_ r.`O9֪>Pmh?=ܕcymK!$Fw.AAұ10DW6;&?&=G%ks}7`{B:uEFvmGZ1_"xNzivt))@plַc`Uş.'kHO/bBa8{1h,k$y4 sSI['3i _@X_]eP??{1NyZ~iGed S}nP߸>'%҃(Qi#{l4Y\jj%T3!jT\Ch*^Ju/r+]r.hK#JI:b@eo)!q̞]gAhXW u+_Q=$ٽ5B.W[7\U<26ac<0`y_7ȣko XhiG LP?27P @wOe/P "gz}~5S2|@˷/0 U} l 4D_O҈UZ N;p^݈ӇkF_r$U Jixs( ( [ULi Ynq<lx5SֆXx ];yi@WLbBΰE־"wV&-iT|~7o9͑`?Q BRLj1َsGrګEDxt;RyW⼋':gm6"ZnUV ׽ѵ 2/-!5Zuzk'~EX6I٠, )jy|+Sr\5?gT4>|[VRb;>ǎWW?ֵj7a:jQ DROyR_18Ő]o@͑Ϡ7({CP8f)id] O,6}fi LGuB(1,֡O0Խĺ\L1>UZOթ/.%vs-i |f("3'9JpLii]T҈WjQ(M nmѨ- cܘj;|ţzc M!ǼK82!L24kA\I\8JBeɳce7zꧠ1[GuvW:~EzSgrBNB7Y)nI|Dmu M׶OI2^b;F"(մN 5SbT19-(R+桫Ľ̏"nvSel?fFA'd aۦKԋ&d80tcƠ?3-2@IoNRՃ9q~>7U21^&"瞟zG'뭧)7UgR۾*TxL5B֌JMٞ]%rO#z4Ir%yu$yc[wx&SKɶT{SDG26NjiYO_ F^)kIn}9L+x,0ÐS_bov} vpC6l(vIG# DC7.mD*csMkXmX>xw 6ȟZ)=2(4ň|?XB@g%~,:G1riIF1uUFKc4 u0.O@mSHd[Mh2~lI;L-3yEVl줂iII洬oT xЭRQ`,0S'-V{4D$btg^N+@VVu"TIJ !&:J{ gP56Fz('d6d,KXS"VVq-F-GUzr$WVqɥҖiyހ\iCk&' -uY$LֶYVjd:{Pwo֕/vS.DC((؆bEA(tcZM:;F!n|[_";zv]Q$pMuxqK aƗ5j0⢄ kJfJf cG~H Xېś< EA|mbꓤ)>3%{h763P%Y/\! Ce VgoBW*>E/3Nhn뀅.ėyqUw}խ&.z$m>~5Nո2mBgXY#TaO?, Y%HQJE f 7-оvD)jI_cL4@KIe<ڞⳈ`,ġF`cx]i.5l " AwzI 2ƆHst_%$!?/> ^mҀ 8M+j+m'FOz8&@e{KŌ>q&1#f4t~gD'GLsr+Gn1OI=XXUEWwg{E U:-Q[b"n>`7\\}{[孯/ l}r7ҵ$Fe; pDY}ZYMS$)*W)}7BGjwTl4`tQԝ\6+P$Q'q[ݐHY=OV& QTl>?_燨ģCse @r1 PId_S8! 1s m YB- ǯHRs\ؕ8])V`Avw0s47zȭh^67W- Ǯ6QcKp[>S<|Euc8m12Fڴq ۼ b:>j ,>Z? %vFrKq[b#!1:CPd'}EsT@Ξd`A{C,zse(zYa< 1iCw5b 7~]=sxdǩWO{do!!HXh0_̚"t"+}9i8V0QDA[~Vh~DA}bu^Lن~읯:c&T܍Ce.>Z{V avG,5-gJ7yvdv"ݘ*/YjPYBfy,:uM$D&c! ERs^݂U+U#.:J¿YNLdzmWҊ, }Cm^A]S='uK` CSi Aloյ6r6$N0ZX2tIόM3B n3҃Qw7 hij -2RK1^szyi*Hx'[(3)x͡6y\bշ(Q`#~)tJ5y (a^'^ìJv6(cf[.]̶\腒"cOĨ\;{c=٦ȔXXGQrfX/*\5SUp3NklՆxZIsso$D%Vs[YbOdczMT^سSҍ ku Dh]ǃT89IюH۔tWͿ`|d r z\;S^Wˠ5 U4IOrÂ9ZѰp?3kWh%uPA>n-y_fY!LUJ6C -Q7#ܴf.}rp*UD1Cjud={-ad0LLR,\?=I(HTN^ۢ tܲ!u' db/lHL3}Bȇ#.f~Be4\'Fȕ꾌 +WBF2"Gz%- ۦ^؟?:0ARk',(PUu9h …;v_\C9M[^-;1!(B,l:nFd&_}<=N:,/<K1 YggW6_Uv;k#lAGb?~ (q?(L"@_y:C:Hu$>pjSHEu$f}]k2s(ڦTn}FT"B;a{1LD|.D\S{q X׊V%X>88x!oKc5i!N`َ=RY=3qvRwjG5\#^Se<5Q% TҷaX].!Lƪa~*pp%d4ȱ4j lB4#K曊)0yBCCF/Ѓ=uA ŌjҁNSS_Zhhv8%,y;΋#yGշԊ׸ 2Wm#ؔtO5Wby.'i#៼uk ptJ%/JTl+djXպ$YVzX*+RXଙH&dBk4&A1ixHk].+[,PoxX¼&ِD&a7`MQ tHQi˭cauW ʆଘumȩ-_s+YZ'o@TL.V\4v/o\qCQ[k$M| `wH}Z '[ oT؅h3rM\lIzl |xqĂHRkʑ%rr3cl~\hQ6paGf^aeYm2h "(gf:hJ{~bk&D!Q#R)TZJ$z{, q!A׫(9$5l;8B#i{ЩpZ>aK+\Jy Ē;VLWYPCgP/֍?E;_ [gP>Mm.SQH'$9:c8 (D9L} ;[mud=JJ yZX=Eʚ<jv]ۨ[Z;l{~1wbc,S 蟲~EZwqJ?^8y̗4&U G^Df bjRMULoN 'sq_f.@xq7RAW^:!)dRShJz9 ]9``)n(-d5v$PhQxYpp? R ߖ<i! !QɣĢL ^G3)0pEP .>uԓ̇Ѷf&(%he5O-ؠYX3M#kLx9mm汋r\*c5Ѓ7 CX#|KN[0arcW޲!ZNgBc=W v_*%|}6hWA~Y~6~#"2lTbk Y(XI`֘M'hafJr՛:rSA(ŀlCNQ@+ G -R.@WW}hlyDa/%W좖DeHzϻs A7KFct1Uzd_3lNjQ "D๏QjEx+0z{ꑫLBfN}!hPՉmmfVTKEwU9R]o'M*ZK;It 1eꛛ2}kP!Equ, 8`bmcuPlRR*f)}G蜶BTď?(-/v-mhsvf ؔQ&{+ wc3 ـs:ߊ1cJU7?cfI? l8`/~Vߵ;[ J16;+OeC/Q hcTIƦ%qB_MØ<͉xӺ{@JGC ǫ[yI`!U9DˁP K'ψugZ h<#4DQ2ժ>-0[؋d+?5sd"A+k8e֯Q9g ̠ \eK4\]6 k^-&5WUkgl50@X8x bn(Q={ iS *Mn=|qM*z]|9=sh.S&piq&!zdqCkҠ'P8!)/Nq^O>*paru쮨jy0,YmٓLxcqٲ~nN yɺ'Y (XY9bmlPWDi9z*S@ƳqmU \lsNM?J!9Hu>W{C^v`7>]IvI34}nut"F>3[+5UEJqmi;@s ].tf A8s6on:PqE~HXv# 7 FF7IS%2?K 0d()$ .J5(aM^m\3ɟ6yT<_RphmxmBW=$ZM' /d9"1@:# +DoW(S^_V3'jo[mFHS" L1y&A wsg*DGH hTu+)CbT_>F9>`C݈|o81xtHil 6L8T<}pG27u佮<]-2Y+za0I ȕٍFٚ/&/P4E=JK*Gjw!'FW[d= M;W^#(5TUyH>P+8])S<·o @: zކp}||?RZ7ObTBϚOhU-q;iS6x'A!keD/վ"y knTrN u, Sj%򇆛Y=18FpJ5;!4n-P)h)ymt4r)۞ -я&8؆MlΆf|#E$N}ߢw CD#AzW`CvT#hd6bd(l?̆OZs|GKxg2z9.2kao:g)2&ۘqgwžw-5Y#}Hu<&.8A!cB==J;ty!XMґH~`Wǿ.o:Yj⠸[ٯjwNoac&X pjFPriS ;>o.qФ]+g^MTҬ{85{{ _HgQBZ];wQ@W^쵬qԋ6'>"ut42'qqH'X AVWJz䈸z~4',$'lQqnSG%CoKR$g )JNڭ<* sxq~ሽE$W܂ '~j` QQ6(97zl,(Nlj՟c˔ό)-砶c0aEp\ =a!AEX) 2n\F'H{3urX׍#3݀f!AdLѐJrj_ JH,vSOmy11"]"̄6@B(:d"C4]qj4 3>a!WKt|vΐȣGa+]PQlB]}[7!X/&ՕhZUI2Rޥ]aks#X(4~[6~̋Ğ E;=l9V xMeIfcc_@==OyfgYV#8}">dS)Ba=c }UA 3;k'0j^˼i}o~Tz7KFh/ig "[ *Y|"Pk .qP/ ]Ƥ .b0\4f[z6@KVU]LYd-JVFzhiA"ïAX]~XJYFX<+L6vM11tE2,nCKCҲlHk:Y5_m2/&(ҁ:F#"ZTQ+SFz@Կ>&RD cВJ}S?8Oybbgv? ,+=IxObfEs+lD;bIc.GLe`lKqLzn wkn7]u՘-Axpk }Wk+C~]*RSvgU$bj/G"/-{ XldC;6HlW(9|2F[[֌;IE* - ߼i[id,q[gX Upٙ Sw3ީ4 Vf뮀xpJl+e đlT'V1 @9F.<`z"-<0;~atqz). ؋Zf̈e}к8Gcpp1ʢ,df7Tt. tSfK[BJ{6 Wt+[(}i2D^nr8s;xpB?ٸ-?敮LM?o|iw 6!EF^lǂȧ΀Ĩj` #U US>AϮw{Y{P}^Ѩ&JSXD0Jr(1ѽjA0jEW{t@.%N; 8\o_K٬ _ W ќà94eKj}P1h=_'HdSIӟ:.-v2fGPBs41'H|-ufIVÅrC}yqf S7o|mm?p㈩-?AI4gpjhȪ@>/A9@;4ҕsDM$d09DC#t2-M ŧ>[2VWZtE,JLgQёO >4Gܕ#Z%*^7%din6z 'Fη&43Tߺ+>3̈́7W6 iHՏ 0)|I-Tz%{;)j/yH*ߨ'kxwtasѹMU])c:Su\$twYwTd0g6{L .2ZT30syZ~רP}I27zIg 6mh@d5k&7_k!t`<%#~ `qchvֳ-B zKc֤(C楄1?5d\19(yyD\ $M[؋(@* |U"Hb4"x[̵í RBeCٴ3ek\U#.2J1Nb8ѥohEՑњEp~Ú)􃿙JyCaKgqQI%t&FcFj@!C@$ϒQݭ4hޏSBjRnu4SLէ,L3DȤA۰+lf#&d&Dgh*}(q=M/ RRN{pkEhQ e;{Py \<%$6T5@3~Ⱦ1Ad*$~WP-q ȴRuk}=A4=IJF̑졾`~rU8-]+vR 6,ݚM7wЃFw=NBj#L"C<2huk~} 3N~rȣRrc'$ qF!dՁ$ ߱Rfr<]~c/j5F~i|\F/OZzl("sf8INӕ;v0gͷ]OF#[1JS6L֢d[C񢫬8;OboPUpg.~7'QӏL&?1[OȰI61׫Xpzo \k@UK i&黅B$oX#w+{#/h1!mDv)*?ڀ1ۣ•mAs zvh=<,/-L3JyGAUWZr- %*YMpް [ä@H)6ؼYY8gIީ݆!> 7dfX]#Tﭱ)o ϝJh@TQ%'zF7q~~y6?/ dIYܹ+$Do{}LCS+,"~e+ze0l4u渞$t$x#cR3-}^o*NYgQ8+L*q *;[;4ryu]18JgKNx2fٛ.! '3IKbJ+o/8_oL&jH 0*}9{TooVL=XѸl^AL'8+cZ3{9 :_æx+ģ74٩Cτԍʕ_*XvEN*tv;_c=+Uq,ivAbʅ":?QQ.v(Fzc`*jFO\:j{k#վSqgJ[֒Rg&s^rrd6ll? 90je?Xu3MbN*m3 c -ۥeУ\j)ϗZ#O"B`gMR1ϤwM<-=D2"8""Ѫ@B%cTgo'P[!'<\UNU\CP,n0QֵirIȬ,]43$(,D[yB'tä Ι 1nUFD㨀q<k%YOBtB+R*3n8U#$efFk5X;Xש?.F`HJJ`p Nw;'3d2}.0d =Z0(̗H=qfJ6"Y&TMv^:vY yyt-G\%qgV'}u؇߃46~d^ceƬ*2v(ek!>_ZKїƳuGp-qtH*yk|𢹼mo|tԠ_Ѡm/ebCA"o2M*OL!#@}6[ygRx\}qF yBv<4vh=qUeD~p~kS+e@ȥ6Պ*Mp`7AJéVUa{R(AB=H#^ܘȯ_diC$\MX-Q Pws]$ς~lwLdzp.9oF6@K>(J#;䌤km\ ҫVsiѾ2,]BU{K>s#NºDzT3Uiβ(<.jߊ^C/՘URE?NlTFk4 \F .GlhKmlE(Xٰ5|QZCBAaa'ГJHn [ԟvwd+!v?QO/&p!_3΍e֤?,';\辀}j#k<@$ǙobcRz7o$)8q²"L:.rQ]!Q0mN'3-7\9脙b|vI+xop{IT\gO.0i :iӑ=l˽c?ˆiu5J@ ?'BHYJ vލ!ւ*m9GA F?oBCudo^!s?-GX,ǍD2iv vi%&~,+<_zɉ*З4'7kH6U3*1VYC:ʽQIL.͜:|0hi9m@XoQ] iAI@bƀBB|<5Ž݄*iV[f0 ۿ-Cv 3G`zM]@uX0KXh$cHDB:U׹C+-.!7;c6O%<7>Zow5U|Ň-2ޞμ'd/d! !0QvGcp{amN_-K(\ka#V| qб.tU3 zQeyCAG CWn3%uB7wm(GaHvݭlEvHoJ.{dW˹佚@p/e=Z՗6f 4] 5BrXtbGNG A;ՍW}t2򈊃] W#^fhG6E>0Ʀ<G|-􂜏yLk&Lީ}[Eշ K fα c(g8w:L FUr7Н hfd{:Ԝ^#aQly$V<傉Ci|}BNœlsqNzq*|8ͥ C3q,X|mxԝk1 w>.8X%NklkKm4gB=GV@&A>KL E3C*#S05UԐtGK )| kpO k+Dͥ NZ)HCtZܳ˔ 5o?æG E V.{V)-/qӧ ~^{"f/-y1aH94 ,!G5\:3BoIj(L -]{DboXC0[h㫅,!Q +Y/ 9~f\u`zb&p y_GU#YZi] 5qs{sГ"Fs,E:zSK h%X- {5~"}xCkcc.Ks|171TUW-' 70ųjM%kbڡ3+ >6Ϙ͡hhYw?:sۧ)|V*(V'b)kcHRi{[+1T&xu_fNqy؛+7]|UVo0ZVW3iJO4h)ǼroMI&lT,0l T3R}~@ƴşkGMq}yΜe|.Md{2떻tS~ڒKʭ  I8a}NeR$xϰгfjeXP۲xc}C&j%^Jw1aoekM/嶒8S1'wnp_oo5u|Ǟ[~KpGO1!klwCU'=͉iղ~b!!ȷZ+m }_X[`Z*|r9MO5%IXnҠf|;.?`Y]5EkK? $&O5 ,$:1P:i6=&= g0mp+')61SqA, ei,,e7-55Vm%1yӪ490xAY7"PJjdIt8O/8?6>qnb2< ^U놄?lb~۽h;4XLH<~op>TՁnYg:]P1OWlogs+z&&-{kZ.$ICҟ=]g5Z3?ݷ^m٤2BT0\PO2q-.HQUx3jKq0fuzqޤ\Dx$ " E%\*R>QIy/sypށ85џu0I{2FJ'Ġ8J\_S [;(R l}pOm"SLGpOñ#_PZΠ96}h^wXI0*yO?Y2NBD2e !3%ceC4"JVSC&KkKQe @ڼұ KzwDU~;T8& M^`)x@ x;`( zt<CȻ6$&wH^ V^[yF3F[Q#  2zg(g?~R h4"9 ktw"1*z9hÞRǂco;ˑR}T,#qtV^Pd8< Iq+ݍ>M&)1(,@-Kk ˘6=%ȏA>k*"P`C8:~h!XJ(Rz"cqM&|XR]C,|,t {rk3 ScgxGdMg{u7t\NRgǁ=9>JBӶK:qhZ1hB:Pb03<,p/M;Lf=^`~~χOa81xhQ|*M{s0KK'NUj=4L"~wqqYi.osmzɢRl4Yl㙺+u~K4zI+(pyw\[4h|C#vFÃ/ɻ/tzu;j5Qe'IKP˃ /됋,qAyo/SUN[0Mw_zzhk5d ?0jA7.pϽohSxOcCŻi突&!3N/A U&ɫ3"wMێ(Jb$n˯~?N-omHTbkPD-]Br2g5(VDCCd~mljTE2{;HM79ұ˵TV,"ZR:t"hN~]ƞ[T`%<1 os?z&PeȌ2JX JmT49Ws*ܼ*tŴ>QnN.m3hW G`]@%y0֙f/G7M4M$.IYD?K3K@1y4+^H{*jX01x;q=z%Å&!y0)PXz0[_ Y' ;QN;S2MN 2iɚM<pa;,C#p3`K$t º}zy+6mJG57j7 6Y¡oP8k s֍fdR /n6H#/E( vc=Hx.T~Z,BZp U#5o7,p8; xnf@dd|5i_mrxWk4#M1)d[W*'iB] 1OsSfM4>AobY2|Abse~ذnX;Z;ެF> |h2F'f]p!U_,NF)B5 `cq.OB 4k~ө ,&~ph\YQИ.|xbtzvba 6ZgI>SaeOC +/7rARgee{Yn׮=%7) f`,bڕhSGBT$r~68ŸdZh\b.p'҆S~$R2<$"Qf)}_BߜTbjI+Ln'OKU=MOW׫ JK"T? ۰ֿHSTO{ܺ[j|1eaқGccKXsL2+ Շ~?[_?Pwo֕/vS.DC((؆bEA(tcZM:;F!n|[_";zv]Q$pMuxqK aƗ5j0⢄ kJfJf cG~H Xېś< EA|mbꓤ)>3%{h5UQ]Ih5UbfL t ~l?ב%T$M>odJ 8[яΕrm3 *.5wMJN:&SD4pI׬,wQp=rٮ=JWpV18}hBI9YfClq`C!qnw dOi _~pjb4Q6VlnÚe^7fsEbv}+Cп`A}6ͤ#B 7G9\qDEuvEkE rf\\t8(B$ǂC9O{]znW[b#!1:CPd'}EsT@Ξd`A{C,zse(zYa< 1iCw5b 7~]=sxdǩWO{do!!HXh0_̚"t"+}9i8V0QDAZ\R~КIa0WHCZ~#"-'|PQI qat}, q Fհr52wf ?(eZNp x`XTݼ-GVv_jz(snQ. (\c]M1of'bs<^4' $N"5 lBZa'&?J-RQcE39TKu'C$z̆„)/(''KJLK5BԂ_t̬*|0SV`J:HKm;L?bf!KQqRCW*^66M* 4,SIdjBg PEy+ђ}+bcwŵIwLQk)Q{<C꼠ZPχWW@ Zi/r"_ ^=F>u ts&IҭDkV> Ѡp]I,NtgnŒaP!P9x`:ܧӷܰ3x(Bcx>Fw݁3xg Ct }Hg{Lcʢ4^l4b4մ4,̋*a]زWr9B 4 ܸRΰ jKKY0#o0ϱ&pWx*BTWP<3 z8VpojWs8Wi4){]nrMEl,w?.ygb%b'5uwnĐ:a-? `bTUb/T d' I Wy2@mFA}\G,1E`I3߻BoWiSKU^ZߺSk.s8NL*仃v2t< JIYƒE5^˙b)d137xj(ZÇN9f5GkXל `IspO^7DZ&<&S2i(}])1BrCws8bء E^(0L( kQe&{伯Uo'av:8{Q+VD"pGT[ TM#P)W *D49J _T>ZwqJ?^8y̗4&U G^Df bjRMULoN 'sq_f.@xq7RAW^:!)dRShJz9 ]9``)n(-d5v$PhQxYpp? R ߖ<i! !QɣĢL ^G3)0pEP .>uԓ̇Ѷf&(%he5O-ؠYX3M#kLx9mm汋r\*c5Ѓ7 CX#|KN[0as-v=~v(Fٔ0hh]>t$X_[cɚdrJT[Aou0^t,jHftz:7q}p8-}(* =uYޞr)nDOcU!QSvq!ibAM'T$a i K~E2K󼈞SګA1WQi0 s4#9#JkqFʴ(;``ffYݙ;u7*k˦V_js@Q >k1 5$EO2aZ`: xbMnB .iD/E+I4z[=-?hN~EL֟ ~k C|n9iտQ eI{a[4eRY >6S }@` qu։&e)LbE=þ~|JX2#X"l6IR0x\^Rl@O7,{ؓmEjW.SMg.|s&҈[/KBŊu]@^u)Eo1ex*C8411F\2_% z=M0圿ͮ3=j_obm`; _4Fց`OA4DQ2ժ>-0[؋d+?5sd"A+k8e֯Q9g ̠ \eK4\]6 k^-&5WUkgl50@X8x bn(Q={ iS *Mn=|qM*z]|9=sh.S&piq&!zdqCkҠ'P8!)/Nq^O>*par^߷=^-12|b̓"GDBaN~D"Ȓ?Xga!oqo^UaRl〇"0f10QBJ6h&Nj܂FJZ˥TM-k5HO2ϳU J-A;-= {*η7 0v/ 94 EJLwһJab'^T8$zodW9H\ȋϏvo٥6#M,aVgZѯ1f#9ub-I] I2zH=b"aʥ!W8 ֛Yk,">!omuDZ[ dJfMqv2N,e*ԄWzi _p1)/3+p˰!S3-e3l_Q6DNŰjb^]k+`=F2ĸibk-gKxnLq|j|4CΨꁙl<;{뭻$G doیS.%-%g2΁q+0kL|8UhY._G<5kV2oM@?]Ae׎-+gb{h&.wud;'S,6чYF'Bشhْ"`YM봗HzF wXn;ФT5FYF` d?t J&/5scϠP+)$XMHkU?@Nkl]_^:)˻s+·~/9-Jrt#f;w>bmlPWDi9z*S@ƳqmU \lsNM?J!9Hu>W{C^v`7>]IvI34}nut"F>3[+5UEJqmi;@s ].tf A8s6on:PqE~HXv# 7 FF7IS%2?K 0d()$ .J5(aM]aA:>/*{U8[@i^->lЮOI,lV~IŅdq^CW%G]N") 64ý4z@OϩR_5kYMs<@3v2Ԧ;olE"Awq܇d_[:IR.zWU_t WZ R>N_WH߷ݏ"M|78w&ك-ʚڲ: 7ق^iz5Zh؋O%J92EUJ,Zc]^T/ 2 EbEP4ɦ2UyhpqB_=/Fa̕1wUx-U̫T,L7t\FI̮dm Cp#/np =S>snF F"кSҜ!d1iw-C9: u'rDrdfj쿔 JŤ*y=lϷ_+3~x#G_T{lh#G|/)°8~)y*B(%bPPIȀ8+:x ѻ\?+]kb&Y *B$_776PDb@|7|P}~DEqRh~m' WRZfa`!4bk`H_zāTf0I$GeܘV1U>Z]OтG^)/0iE {y/N lI)C! )ք.2< Oܩ襶Nsp\)&7e 띙ݿMW>$zǔإGPIQt'ʅ\N<:+y_.V; 'U~@4 '^{)ѯjVR[%Q&mWn::V"ZC1VS^;&[835^Zl^> "?g5*䱡nbY=K?TAyjᎃ?,/|»l8SḰ/^hZRULHs;40U'c2,NJVa֭h6 "ɭSϙQ=ht`b.un)gO Є2d"53PM; *UTq?GՎ(U^iY`T%?BUL׻ @UD|{ٵ+Ӌ7\U h]dn0UK4н~HQzG9 s瓻ao@W){ o~1 twHnJU> }"2hme:ǩaڸ^qh8~ `B$!x)D c o%2Jg$&ɚɾҽܒ`PA#2(5GIW9(Ѵۯ_&*lH,u<K>k.?+4l_q]0x  vRw`٤9S2. .*xWmաn,#pp р~5Q(d( !>Wa_#upd)Еy^IxΈ&1c) "߉QCT$bzu4EScJk'ZFZfrZD\ܽk_ 55wˋR;F$!18XG֊sFn XrC#ۀsŌRF"jTHKf׋%' z(I%`R\(SO<>PU˨X/N~-v E/?lcNM=0Ą~ <ϱԟed f_%u) >QY>ZwȭkZiGMOګ.%"C:ј/AKz2|>U =h\e#1' l94׶N&zA 9d)ci$ҷ^623)‡5jPY_JW$ @rwzس]Yw֫7ʨC]ƙ۬~סTP/=\bNW-Υ粴qEuEd%Z thoc1QIlPOc.-6/=ճjMu]hD"6d̎/jk7?CXn8k)P38TēL VJƯUE{'Zss5y{>5W]qD]A&:~ĚorK ?}X 3+ .9Eka.Y%Gui^brM$AͩxR94;nȥ1L PgҤ;I1Ϊ"?[86Hj%1K]Iet nf:֚ V+Q5,I.]5+~ V*᥊ ȵ[T/}(Ƈ1ZG05@[ e f$xniTHMȻټ '_N` s_F>\f~Uv3(-18qH~] ad_C3l=3ZE\N+&?Ե7zɪD?3ѿAQ#MM,(5k `dJecY~)XX$nZY6 vV32dThuD?rYm'/E:/qs)s>;7~p̣Xkx4k0hev9Vqz3;vF@-쨰$ڹ?8Ex;?8J=. ?W.B+!ߪKGinԆi|!z..8PtB}ݎ8S*]N) 4DwrȥY:, ^-rY/{ߴvlCO¿=tw8*k'E XS$QDvvɉYb0T`Opl{* F! u/EDwd@g@?SVooO ']Oɿ 댉250/PFNb]↦ZWL-fYUng! _-*1g(t="G/lk- Sb2IKZ*WE=*2ҝerN1\: <$/9/;d8,lep'&al TPvr636>ܞx)LX )!p2,'#_uo4K?|`ѥiJ}25jBa9hg@MGp cHUX|IhbR+4J%LdCRPj$9mֆ@sl݇1zs/YZcDNܘ$Ԩ`!&m-X}),.gNe$=v8<(61i1]LowG|q}OB~'|s*pEX^cn 0M@||g<ČqV[n)gd )Lڻ)np$s{ׂݶa;|/!ʠq `/)(\kāטg藾ffh${e3◡w21X^t|@!$?p-נ]iWG#P8At k&# aiHmd0/*kH02MGR#fDDS$ni.~V>F:H .5*9|eIԧ,q=xC5 Gf NPa|Vt!1JWi/I¬ 1U PB>ݾzg鄋eD֩XRiLˠ9#iRz? E\$/y𜴣s) h}E.DPmk\u?ah]R0 m.F(X0L6Rtxݔj+B*TMLED pOSiM7nܔDoO6M b*iJz$! DB#Z č{40SPz:A=Q7/߹A5[+AIZ,a٪wo,-4ɢ*oVjɬ8F߼g4'z>ۗM|}X '5**zB©^W=@QN(:qދ)8Q^zG@4mP_dVC/PA2Zioy(ʌQ4?d| z\|S1jP-Wp+Қz҅I!(N'eZ tA ӝX )-$7?nOҟb<}j5vPbǼ67(-ʘtyuJ 5]︢3J NW OA!v$K5QtҪ%fgaRM_pS _Z7f(JNpf/|MH?!Ã3]RuB9ࠃ7P3dr6>g[ڔ}֣'O]ѼBnu6ājUZ޽lS%obt{x lHgQBNgs4TD^g*X ͥ|QCH:u;dݫC41D 2fV P"`Kkh+GJՀHkͭ7Ăg>/m.yFuD _75,>~H>,5莝;7Y.7DDz9orv9Q{*jo:&uk7Bh|m:n)wOMC*f4z:DNv jrir~w!m@!\1TKi+=i xzts+kkRZNKdOUoZ>xZj'0WIB Rfyb©id^s ;vI]G%6NcbjT W> s/Z-P;2 Ԕ|m[aPPA#Vs ã1ky-jišYL{~]| OBֈ*[2a)3ʁb9瓸kIl0sx -{=S.{PGV\Xx7u:֖HN8 ʝ_G h %*)ZF_p6ݙrRWt"P3S;4 %GJrq>KL3=@AdYǫQSH×ۈ,LO(l!1rHd9#tfs Sty|Hh  2O!(BFo :O@$tKe?2}g-n8hknL)S4xW!zq&SC;,=3we/J 0MqJ&XB&UQjTX_f5wK?- T"sZgmV cE+v솏D9[f(JouColh zt﨧v`|.vG]8KB&P3G۳^R[Gtn20RLjlܫYDtvoI$S A@GԈJiXrHӤ}xS5 >KTz7)MvF?BTkQ2UgJHpb!|W~- bK*h4Bj$9c/rWy,> 1Zn%TB[oۼ3詩f3g+;8?z܏tfUsY|X D*ܕ[Q<.5~ЍxzYz] E/OxҐI@%}m:ILr Ulegxt-돃XN;řmpz8Pڃ9_͢Mh7 Y{XHc뷗fw|@ E6ӎw.6Ǯ )rg eR[fv" p}*n]o/d:+ޓ6\@ JLl+3r&RquZ86́x^?kC1+ّR r\u; ].=7iO\'XcudtWrQV`"[IU< ;>${%[T8l%ODe*?:5S9":f77;2U6ۤhS0f9n[Wܩ,;<[h{af͂VĭduC+5PUvOz ڤ`hD1pV :n=8knx9P?:ʿH}aRR;[ ƴ_@@ܲ8(z`4X07at*"(5>jek1 `/P:f׶(Qs hof1m|:KQN<>NЋfԒ1N1`c-J>J+vѳueZ^Wp'483̬+QXXJPYԣ+MM<9=^zO.I㎾ f_cH\$i}ӹBtK;XW1%Rz6"J])\z nh?5>!J%Saj0{n^"Y=n2߅vր,&ض } B ׸mUyHyJ̰WWȹz&/1\A؈6!0sJVRD/'x HU+^c#Ш 3;" $p^!i>PfoYb!J.JGG⡟y#>:W35Q߅(oсC)^R!b g4_e%DrTM!( #L54rݏAKTg*0c-X:$z+zl)ంC#QAzߒH"2(uo< ^945S^_~)P5y ?Y[oqdMJRf_Å,HqgݠX_XeѐdBu}ތr 4g v.ukGuBo Ά>qY؄"߆d*BM6C6U[f{FB?}5!P9ƛ)zoG6l KeZ y-)ye+)*&-ٺi- e|GAߓr21 K(r"iĿK6o']}0 ŻRhmx.-F{J3 E_G*O[e)7_k.Ta~>\K15Ts[`RR"bn4ܧ@75~eGF aw:9 *nuQ2p!+{"2"[SxEthgq&_܄HCkuf0+7Anm%@qtjmlJS&T[ENLǖo=RaVyvNfa$# M/Kܭ VE!uhKص/6;L_X>F/ eT/C{Oq>Nx"71O,PE5b%.xyjOha0>_B*xҁTTw7;Q@gʓJ(;= ӌ? gXT^J'z s$gk ʳȯ0p9c>jU3[aSs&JX a5?ȱ4&YxȊ$ԈM K&Xa%L(6A/Q%u!.F \HVm1$ϣ:nsrnSS#Svs.8S+;4ϝƒ ;9o>Qf@ YEKOq`C-.Ĝ,ͷ Xtkc:j .R"_w"FsDƸaیh.?mW Gɜ9ݝj M\׶0ZRPGuߝ? &? ES:ӔT^<͆ /ǮƷ̰Ў󸘊MN+L|͓(xUz% 8Z..cM7UjOs:D)-c>|M#vƛ晕) zd^Rb_$D:ꀒK(ǯTo(˒iAA9CsR`8<#& U5 iwޟ)ET #d(╲O5An+;oji|"W\ϛz 5c"xu@ W7)+0X"~^b8~c٨}ZZ$= E}+!9S_ HaWS?ڪԔblƂ]6a)"gU'$Րx{7 )$.MUglO7Pd`sY\BhosyJ >Oe9u\ؘ@їBmCŇ);֚?f}+1Nޓ9 AF.ѡuG 4D)\QVC)]}ޭ_]zϗjP-gTu}Үև^-;Ipx8"úD|nn4>Ov#D}V<+iH\˥6+8w(;".iv]lşmf۔(M ,JS?Hd (o 9sZ)a`2›$e9[";hLl=wM|kpٴì&Nm%e؈&v k_g(iF0Bd G7gpj2$$ґFmhxwh͸I&7[+:hq9j(|,G|QQYr@0TqM${ bvVwW{e/],Qn" mϝK k;c e8Tޭ`|0\b;4J7OEyއgG{bz8ɓX`֊,kqȬL?Iҷ6܂O/[GڌA;*`&_ gf+O?hOJ8)B/JK~okiלeCnu!!S [[З w'"ȋUl⍽OehWN46AW:HG7$}9EπlTDy8ZߣG7CȘ{?CCW:]ſ\?K[f,#wߦXs#a_P],2kyA[CFj82_9 Rz ,.%3"xzo@G09t;)_(>7iߓ"acsY<.ߨu=wJm;uQŜ6Jev?*|FWFe'U{I5mt1M'"OY{34ˆ8B5)xQco*7fyIx1;"J Ni^‡ *\̽RJt]>xŝ}SRV/,}@upNħ9'}ZZ$= E}+!9S_ HaWS?ڪԔblƂ]6a i$(8%pkV0ǦҮN!F2Ď}\ _41cg"d] kPn5/7 Q^)j9t> Tξ`` xg5&*b೭" 푍9h*<]7KJg~W1$RY]`w TIq`?,<>vnq$H֜΍Bo6ɰ͡j@aR3p1 C5V31:w[8rGx i$E=j:8}4dl^x{I]8א@^gJ/UQ pD}m-2MF"8^˺ AHg/U˚8SmX5GS6U0q%w*q+n؄ltXEUt8L$0Qr=[T=/(<*/[t8oFr5xsgL4K{J ٶ;H-Nz|xRkIADF- N3 ؒ{&! K2GZ=ۑ&ZPaT0$Ϋ؋ `Nfx/:,y9: l\M'0Kw7T7SHo=ԭƋr U3|i0\b;4J7OPQ7"8?"+]M aN.'{A60G8B` IQ' *otUEz eoml*RlZ?{@ Pݵ( ,f/nd"d,a#w U(v}"# 'jU$r?tف-jmBS.؂:9q09kX}es|ϯj~UeߞߞcVҳB;-SiX`$ aNkSkn)мghSQ`EO2%!ZgFK}k#ӨU  VTŪ3%&p>hVBr|EuF0ICD֪zr߫eg82$VE<ʕcRёP5,6Y6'6LyA`w ;RG0TZAMa/j,UHέשM_T9V\]OFdOl+)<|O:n*x'f?srس?cns6`w=4W[iI{Qz$anC`@HSTUŖ$o׼^(SfN6LRrR׿+@;s*W|:n Ӯ#H-χ0`'vܱ90\fu7E 7q; % $Y@̐l4q¶A]@Lev5Ŭq{s-CraA9}zxl~X/*v֔j|Nfs#Fyv罯NrM0#[-[:.S_iN|80KX`ӱ%ӉQSo, t6;|EW=#tsw{' wDtk 4xX'&(bJHP3Ӈxů^C>jMvX"Rd04 rKϰ8_>lxx?\.=6?Ə%}]5`;%" =rAȥnC5@veo$W=Px8+Q|>k:b-y}B2?Z᤼X8|ϒ ÓZ3g\s&u(sp9H{#['/H 5uP") =}BdJ'!i *;l]V[ #R<8 TR`ʎ!ܙyHE$TYvpeJX<hRM\GvX;e;UJSuVU={Qۑ"@Bb=c ]\R$୪ǴP9=qjׇBJDX -WIf}tED@ Cbo)˛ /hs6'J[5yܕ)JH1 4Bp>gɿسȓ7K\CQ~ʱ(/\K/Ik.Uz+{c8΋G 8f Z 'wl#\:KfN[x2;Qo)lLu,FC\z~4>" Epն7 $Kv,"0߰Nƚ}M=YY*V%!VG"YCX#"84lN&ښS8:Kl 0y4=-,w5Bek81cgJ]gQ7ügfW\ntbBqz1JhE$ &ʽXW6V@.4 (nJ-;sv !jw(ư޹-7372qµyaq|VE"W7Fmb{ʑ_3GAEuEq,Ћ8?:RNw[HkH vUjdH=VI4" lGiϘ*r~.m(-^h|K c2쫮sFsHV$ EۭMcj`&5d&/H_>Ţǁ)`*K-o91;T:lw$Ԇpr诃 ^8*j6.|IIF6!"85zŋx )x11U@Sė2 Qe-ϒ#Cëdi@{qhvr Y^Ϗ륵Z:,%kjDB#WV@6ip"*ɩNKc >զcѤbs 7TJY)c(q8:5k&K]x+|,רhU1+Kʴ~$EMzvᬞp3m=Y5?.+m7MU52pI*kYtBjI 20ρE ܺ{A&HWDgOsa`zѮ tLvhQR}C.V`e*AMؽyF8z^F95sy'5pkR",tgSrعYU0Q-mE~iLe+bJ nv<YJ{aNk]E@l;x6'&zd(gp">>'5֋juo&^`oǁpf40U,=pƈAWC\}y?ʤ@hڕ W>1u.'86$rʍW a*Rfʪp)=tc~\Un #iFotOJ~h m\džQ#?W@EaF~3'u]os$#芩(/ $VGzS9}IaMw*C%jSRB0e91sJ˽[=}1q+-jYp U.*+a6e D~zZ=s @o@ >ssZ޻h˖pj2VL{G\l6v.8YMO1FUCv(Pf5~=ݞcxUGI"ֿNUȵ, WCզc$YbX'lZ5|x =e@'O*LKhH>5 z1=^޲Z ? Gf܌89-+,@3jy]A@ ({>nf4~+\? bn/+!ǵK!J[%Ry/)nB#lc -f;|%!jv&gKɬ̷Ū^#m\,\+k1p&.dh%.I܂Њ˵)JYQ׹-nqZEe7x=Y'W^lJJTT/rog#]*xRVoML&F MϕMa5ͺߪN J{0[^[vsVZNݙQ6+ 0 h jRG!@B?Nx2*LZqg4B]BZPvR!{߿&)Rk PQ|V`dLj;ghvdf> ކ^?\H>UX+ȁMD?VM=GV 3qľ[85۶T6^^π//{څK)s>i3m='_aHT\մKW'чH@b/2]/@#d&Eqt^Td&?eiԑd7W,}C"- QvnaHyOJcCW>FTeaލd LJy+$G_r8ωǰ:FIK(E3}" ^(e.wT˹q27VpQ,_ߓyt:޼S6t -<ʆ}Hs߅o yAoHŗGk]mb~@lCPD2 3>ĝMMۋ$W]NӋgftrl{/N#m=[g6H3#_tpT%2m2BRjikI/%q|} aȢ,MBogrBSaU)(h>0f#?Ш3LfvI(AqNv$ב :'Ov)w(a;▦3MCD釲u3>eRux]Ch\dKA'cn5p"Y?_|XF03Sl20{n(j;oqE:$gP .xY`)gt21mSz6hCQK t;ʤů&7۝1Fyh}BJ҃ρv&q'f=En E870#0w!-|x3St /٘O )\o&bOZ! V>UOs'V0لYhg3SKT&}6fK'$XMU|Q*xא1q 6xQG~"OgG}I訂/&k͘ኇá׉R̩z#oŊ/+Vp YR# $ڗk%J-6]H,ʂ}HO)KI]Տ/>LqAS\\o@-UNsIرм:|h,|aPl@\3E%rx+ƕl=yw7-A:sA<!"RsNjzs5MYhl,{Q=Ѝg 7͏z\.FZ_s0:TC }$cC@lsYweGxqSVHȣ$(WCg O#V计j:H+cv&^Cf FuU"~t;|nG,PL" НQ~r̀sJ QDGUXo, ¦*$yG\~V5 Su樵(D?*ҩ-GǸctm!^( HZZCLu짥$|#{E=_݋E {%M{{YBmGyK8_c𨼍 rs4|/ /,~"j'hUIRzjq ;_VBW"OsDnI:ٺOu^06[ImE1-D!f)?4\^$)S*"pzA8vGFt}ߢS憎"!x8="62Dn*$û͟xz]9_G1^Ϥr 2\쫮ˌ`dk񩋁TvTmmS@N`V0.U^U?m_UGsh6E])t[<8M)Z_({O5{yO%:P%o6)3*j)\f''q˺;OϮ?w7XfFnvӫ;wE댘D<Z'hL(_ijr3 1t]uGbdrE \ՃD&d/#Fkq5ͳD78nMMۋH8i baϨxJtk,E/]d.vmߢqW19bZ#i7֭4w-8+v)5ƵyCt0p6ta^z vn)EM(XtJE}*ȱ8 ;Ҙ8 0ˎ% 7G [1aRm'"鄑v0yӏ_Y{IK z tN;f%d×kGy=ϐ}Jxx &dBӎ(qIC\< tQxw$"$7z -AF70 nEhTH@:4(V͵U%ϲdb%ld> *ϫC~zoFt@+a .~!4r% Rm 0y(<Y'mh|"v?3bt\K:QФtR[2 B*~N8/(A/%iNj0Vgu|9!a=C@l.I@,X;4)fLIԎh*5XnXiK:d=}fU6)d!aлUF)Ì(m5PM@sE?7O}uSm[j`sohPԸXݤf_r Q4xG9?ܴWg3;.y#yK fih[' 9,JvKqgvUQۛz2+X> 3|1<$Z`Q<'_^cSL*dlXC0m+W}RКSz\`+e'YV UšFc9`c>$ʴҮz&D啛vM+ô!/`z4EBe(٨"nb5 n z2d0 ,^A~ʍHyمKܶ<|'-$vÉ=Jw[ybr8Lf ԵwY+j[YG{Nldbq i?4(MK7L?E{qޘ˞ŧ&&b ao \7m$5>{e$HڹT}P]whgP%2bٴA@v:A9 4w?O qlV~fPk7mm g߲QZc:9DvY" {# Ӝtiq:@c#AgB'o/yx#ZjO3<![G:{,xk>c n2f^%o<:^YQWs%vs&E]sfd&HV+;mMFӻ&c0ZT9j<O ߺVpvVw(&8ƴD;F{dQ3dwˏF 5 c^68R(+ֱn-a3ԩt;!:C1MD?x?qnTD5Xjmt |RJX֭>r9?I׌c+Itq$EYis86>Q-SWǑۮ(|ô@UZVj{u{ q`67c]jr- -Gz(:Wr%D,*NoI9:ȻP8߫p gjb+BÞQ?6|;@30RL5pw cęd]:&s:W:nTU0K};uP'=݋:xLԨ %i_kFUxL^v,@4ki? :+ڥ?#<1ؗ;G액AFLg^%β{w9OsvK#Œ;G*6[,gȞJtERl-.MZy6J{FpB )2M7"%rʯoVI fhesHPTo͕s HL/ׅ@\kd`L-pcN? y;5=Fྡe2 zh(?Pgq!KI[%;C Vqd=_8xrγH֬7j GWbm+YvҪ?K01 Lӭ [a&I"Qj"f+mg-R@hJނgR drl91 }CQf.\Iы"Vϊ'\^.D(l53`Rq۰"eUk$AK*Lwoudi0BO WeKl<}niJk*a%SiyO[N:W3V.C(n" X5RUrjrҁ7V3v:VrŀnUhסebD>^0Lcy.vw(`LɯOeJ}Ii.zq|VE!a"Sovz܀<,8<(a `+734F+&?!E̲R:qD+D&U_AR[ZD‡A:VIv>#u!/~rV眲>nU?29s. ?쫮sFsHV$ EۭMcj`&5d&/H_>Ţǁ)`*K-o91;T:lw$Ԇpr诀]eM?O_dV6Z [gA:ƴ ).NofE IV2$/? AMmn,\LYGh=8͢7GZ7#׎^Hw^+eX8e(g)2JIi~!7`|%rX+bhN~jYBu2*Ԧ%7 dX.{E~`JJ@n; zSkBOD@:DT׮z&hJlLHQ|I~[/|&5Zo6-9 D>C)IǰBsjɮk󓩓b@<̝#Ȝi}c# |n#fL*_|ɶGDl|w041):pG|zw]TFgv,X,ϔ0nK1=OI]NZ}UN>1ЯH&V mX'd--4~JkK-`^O351 DĴؾVnw(ܜ/gj4o‡Ğ^nCb1_G#k3MЀ"-ucv]vy,f"iMI]y˃Rl_*cOWQy[ZIͥ!hBd6y4=$\Wtyl93uUs[Qb6R;*uG3=ÂHYw\B2!T.ܳ.@S$/l9Ẅ<@XEY}k9zca#98@$;- I0UQޔvp&_RX{~N8 QDn tY_w yѸDmw[}iBNW_\fl.+'_ O*!M"k>{1 [drsJunMGkYɬk=sgݖ毛*h`b9L-K ]a`pTtFڃH&Mjw=~@\)S!qa0wbX[H9Y?s/Y}®bc#;؟#>}i&\itt9||sQ'#׷-iV::;}gf1IUrʹr<Csg{Q꿰AWTW~`T/Ǐ}]gδukN.8 24$J:ͬu,' X>G<^a FRV *k|YԬb$Ȍ=Ѝ?;$)Xhh( 9"q%iNsqo?nl2fVRʣ(n4O4T5nn]EWq|@ɺE7z8xtz Go(^c2_'Er (n^g۸irnUܲ.rSQzvҏ6$(&*=𧼵08WNgr?g]jm 4Q3|S ru IeyM߭Z6qKIQ\\<kML c 8UfBɂtw![<95Vc#hDr=A 9f$DsqY~FܩX[[=> ;~ksމU )f'%Pys>N|Qn޻8P0Sh ҿGMj }5C)xEu3YI W]t-6NI!bի1Fo>G:&[Bu! `?`dij_{rij*hR߁?NaufhbD'9D6q@ O^l ;\UowJ˞aT^: Z' nRD,YFe{cPTϳۂnor fwN=TKA^J=U(xl(o'U՗a_!ߎ.9/Ibf* 6z?t~(9nη$Q* ͖)|)B xihr>쟥/I(tȭ-)"1\_]`,ER_cWhO6?D;~+H98qn lU ͡MC\zBֱg.P2hoF0;vjˡz+Q vm}K;ni HhZHzD+m>LAUQ&ߢrOD`Mm[]qW*2e*.YVq soq|4rh +%,h3Eűn+QG1`3[%du#ua;B@Zr)~j JDX'[%(w66mb1Q^/+A׆Ѵ]Y9 `6tv Hw)qTȑQsf5 #|~RbMRmm dMjNGY7I{QV<{Fm/!c MO42>]Q׎wt;Z52 8fgMf|AY5YR3C JBx0uXy7D*!Iw_f=1(-6дlAJ'~ʒn*13YGG?R8Ћ##_hv{a }@ECeLK ىNv?~our+˯wV?l$f l'VSuVg\{*MxvX,:the e8p7Կx LԸrPHa1@nbl%51O;jl&M)w;qA8/=SyWLp گp赟$ٷT"p(Pi =Q#7Ċz0bO1h"µԵ+Lع6N cmI ҥ7"֜#Tw40Wglvi&GF*lFn=-?b*]!j 3$4eLãŁ ܠD,;_ܯ&dx[ Ο:.*XhjCwدmtl~7ΚnGM,KMuC ʀc[z>]@y}`߶ԅmY9' wІif +_⿜$o̚GJ3@3 )kblZ:HY+/fTW"P_H՟ [YW;/70}4yѬj8<9xo;eղ><]p>2J9pq*ȉtÇn3c+ 膹NE6*yasMe¢Ľx_W="4Zyj: 4,/ ("'t/0ɏLڐ{1eA0KXs'otZP cIaD~K [hLuAJ#˽zĞ|c^SչM|fչw~8`INL(JU<ʴ@fuLTg~&@(>'b< ##q 6PN&d)>fd p \]Γ}юO?1kDz{Y;/0$C4#cegBO?c5y.6N∥AB>q!83 o1 c[ww*Yt <[,۽wu9a_Ka:d9ThELv&Ѯs>a(5W~ <O3E'FˋYm@:rcbRA[BypοTw]KBi]lJmЄd7 Zvm%<%n}/':{-OT6\.XsG|s.\ :Կh&"] Կ= wH[# >9g E|J.&\3I(zHٜD?e0Ʃj^Ԗ Ng)=F/LYIIar4Fg5?RǠ r+8hĿ_"Ovs~0F֗%TDwP4qЩCp$%}c+t ?ҕ769~o^ @~EmicIjNo⅝h\0g@~A&:'$oSF-s![lzL/DqȧCEAEzR-Q}ERL}!ԦB/ Wǜt-6?^|Ul,gX&Ұ1mϬY[1A)DSZ3e悂bg4[FõQM0!i=@6vO@Ҳ{;HV~ >kޅ,e8?&6JAJ5 D'9ҼWpv't/%muog(x&RR!n[m5S>kO:} *JOr|C<։c3p 5fge$y%,PEL1aR;Xb YQ~uqBiPXp[z5XJIMi 2ƁT P+Q(|:iþZ2k F=RQG&js"j?,GUжJ m_% u lcٙ־-3LL9,TB1Z%r=94Oϼ+C|5b3LJ*ZP #:NsOEsQa_MDXa&O# ҴSL-q2<\Lp_YBr)uW2K7Ȕx:5(?TB0W1:/WKg|ns!mYË#~=W4oձtOo@#T]};Ǔ]nxWI n{蝎 q(^C#"M(%*Ww?&T"!wZ?'h(CNf|fVPT*V~T!(b[#$P"4fo9=VAvgoyݡ\cg.`cPO̺L">`a/E hz\R[ߤj3 TTzr ?m Ak5ZD9eYCPu /)pŏAS 'lTL0[*l>ftZ\*~֕Xd[C5m= aBZ_&I/§l)ZqR tޔEb'a]yj0ILQK0}߁RYJ]`"V+^;/n(,, =ZhA;@M3`/[=q$W`QL%TNH um됉 zW #9a6 0[S8CQHْ )yq}]<C{o&^FD{_t:ϩ W I.Kw!Fs)f!y3B5O ,[)~h3-S `DID ό4l}]. ٝq=jvaƼ=fQm]XMPW;GQ6x'hʣq˹!'|k՜azck~LYd1;BrF ] #lmYJQG\4}#>lpcjⅺQ yIm J]$ĕrDܼk}]K1ZФUvFȶ+fOwn@ q>20+zlm `?ސL!êJRC;HFw2~?,M@'u"ȏs $hC }fʉYC` 7 '9iD( s$G nTav,qh5wkˡy͙;'3.-ԗ,ʓ )vFfX Kn,YJpjv]v +ƒMӂ-"Xt^gBGJ4t#UI>o0YgonHL osсô.*"ili2'z+)y`rB&z: a my.ݶ׽&KBPnmrϿ Z>}N)|회.{1 osC5f(ة)qXj1и'*'#Q0]nʍߥ485Z՜CexԶzwܔ(lXcf:͕D,ug牉aBN}ݱ=}k^˲Y4jmZ3i3Ë@ŒWaUdžM%09zI ͸mD$%'=GXPUZf8I4,J!#CGoL,A;0j"[>}M#֞YEq|*Ĺq k{z^e>( RX Wh3"UېVJw;vSsDvE&Tܱ\6/=l0g !8-o$M -m g~I"W֣>tq{9ClAewFYN՞9`N\o)D:GZш](/s *FzV4ì ezt"R+8 .@ JcE 1@7f3 q{&¿F7TWeb F*Z#SOs^kQ  Zn-іrSmLx/Qψ︡&`hS2wR!oT=ZTapFppxmn4]h-e7=X(iNMpuI{H&mLJ"7L+< [k /`IR'/,dR03nSj!Q.4xG? '79Iۚ\ĭSG47lo3V uq:%HNG ɷ[=Je\Ħ p|kfuڎ AU<;Y~y=,e3|(Rwݾ2@GS,!Ϋk;#/$otpfރcR30? RHq=BJqtVk0LلQOօ4S$I]|JݩUf\#M68 LBRM$j/oZSBW<m j#ԜEgU}u#{-QJXĐwn2Mс1 ״K]!%Tv2l_ ㍘&4P O^ƇN|LWXG-<uR^QȼCEL;~j(lX6ZM!-?ii .` +wn Jv˅h``uVЇS7|fF"@F,DZ&; b#~n#}ҁ8'LNN!C=e*a)::0îR>a"t5 /j29;LfMҽԕ,W6#4Zt?E?Z\ko6 Jlz@xҠS<:p~rh瞯\ {Z`h hZȕ#EQOrn) kaXڸ_LG+h=.>Yx0(,r9/.#THݪc:nSW1a0vq .Aҫ\pt.22"R{)afNA<S ׬0׃g g ?p5pW]k.Vg{hZ-+  +0H"bkqiGvJp O3#6^R'Jm䃐1 kbo ]6) {)`yN3=o5 ŏM?5g#}vᒉZ:QUи MmZ䶰۲Taw>1046H{b lCnDh;J`is)Ys;̊_&NܩىЂGSK!ISc55B iaf:8EVn2K(9g(~LV$2a". wa$٪ʄ_'س֮/enb0X1jC#&Ffcc1A9;p(>C3?YW nϡmUz^9V ±չn[u Gy[gZnN kTӽkZ[ʪxv:25kD[. ڢ倳EŻ/BɨzJX#pm3N%شUR 8SMBp;baAG!)Ma%WN*SƲO?EҵB~h7:zte75ԩPB"+!^ X.&dYT<.XCĜU'4H$Z1ƴZn4X) ay4}wvi}8a6 *BO݃HVG.GS-W5C ګ/Hn:}LeGLBmGwTzJK\|~GԙMLr.n~Hl_yUʎ/q{'٣Ƅs33Bvwcjr{{Sl-Cd?T‚Juͷ_WvNԨ0ص_a<[sEp{}kdsb h$M|mSQqt%pw3tgp2/b)wqL%X,g}uR-b\ihuKl9[p~*KPz=9 k+MVK|8`IN7u0ڔTi_((.kѬΆ`4j3L!s*GoŽ4F`pZFf6DpΞd<Ol_t$B\4#OTD“uaOE]QZx/g:̐=:՞/|gI.Q 6RuȎ$rOeMvz6f]šk sR 3SQh}z2N{k(i?-F椧V8)/L 5$YMoo>&F^gMc&G "J⛸9R8㪆AaK⢆DOaZnٍujM\ nz}>'zS ]lHIJT[ʭ$( `NKDSiv::ZFWW۽䰙,0Kg{G,vײSK% a4@ù̽4Ul;%ʰvH, 9+xPBV5GYk- pfNClVO̠RKj,(:}cALdM8أSfٽInxbHv /f ЪmUadhtB|rf>bOwϹFPorٱJM!,D:MJ ]2{;\qT,XˌxWѮ+?0wgohBw@ߧ4 ]X:⬻cH pQ!x0*t@}ҒRGPa{5'M^Xn&W[3kJT5ky%JecA0V7zAeaXH5QKĆ ^NK'&(!첗9x{%WJ̃ߒ:vLÿ3&Hθ Fx v*X%@<,TϭN4 X]#+OQL&߈%ָdK']n{%Kמ .UfSWE)?k+;H0ҩ "8kf=d<n܀d_iMږp,$?Y^ս3̥Q \a3pAL+¤垐ך>J&dnq')*P@3_ c8ͱ'٘Z %7S Q%A9: ;䉑v;d});HӸvMLpV e1Jߎ|xZj,~#ku?Mp52wL+UX&{iBXgL!=$>ƽ0)"II,Ue^#z OUMMmt>ُ1{0XtddΕS*:U[TO[ 9 k/b-Ԇ #|KL b*PgGye$8-յ{<.m^]:lbBTC a&|Ma}:DEUIqE,݅AOJSLFq#} Y]O!?D{S%j%4G3`쉘\Z: SZv\7KUβCmw$~񳏙QƎRmkn4:@ueěB$x]5- ⑧o͈UCy\k' HrH.n |:ɗj<ć>R%Zkn3KխzX{ߒV#7͑ڛ*]4EI'R Oڠf{U:$%:`%v+g5S0@ :>";nLqzL/2<4PUA5Vs9Ў[, Q.IJ-kA(^fdIaea+ _3~( !z<(Ak13-j\gFfu=2A6pU\C9VY6,yuXuVJ3ngx3&,@QP=վ,7hD\;1H([f¾Lvkc#R*rLuе o?M/ߎeY 3j%-Ur,Bsw.;d|vE>ەĥfpNȱg}D yRseUD<ϱW鮔!"m݁aS0_֒-EQyd"(D^UN2." 0/o pnˌx]@e.$X<~TIsFѨ@E8bKQ=]C\!PM, K/1 vF߲,1mh6`њ#eOs$oyaG߹!R'=3al9%y>Aa{(k7g4, 櫜R! 5k{OIq'-\GjGnlԾ/ HLGy4kQ<ɴ"n9BF8q8t<&X{H%Håw 6sf 4׉|ɒ c9MZ"gDF(e^@ 9I 3ce04N@k9J*n@BG(¿pg8L h蒢WGo\ĊڸG'$hM=[ld@j2+3d;ʺZ$& 'G > H B;(2X>F_l?d<>zxpuef{ m~Y% ef_wuR`ۍKETn!GDw?'&A0Sɒbf}r5.us\j#+H88l€ zQA+SrKx/U{mTg]:Su!0'e ݋7FD`C0YG[5JdO]Uz.tT ͻM7x^VtN-*; opPq %#:z^qe`Hg kےv֮bT m0Ո3Cbf>qށRx來zvEK\_\fPv-ID/0 Z}eާb&1j/GI`7ȅ2C jWϼ`vEPA-&݆cȍ 14 26.BLO.WNu0lndF%_)VuDRJ]xԂ_tUQWbc k=Pff!jdәg М$P(_4V BFYF߾;5']zW:.3|s^rCckQv`5L0˜p` ͫ,*dw5)LWhpl"Quz*=ߝ蔔6ڒ¼\Џ꠹4ξ.-PNFP%~~٠(= n La ,3= ]妰aÝX"qPKwѫ=FG& -K \X )gUFDo%]F^pO Eѕ/(*BdgH̟ 9DvX#SE`0vÄwhhTXϐzZM+AHg?ha"昕jT-dGq@[yAh{ܷgIO2vjNJYhTZYb,(U) r"DC?,)T8$9hԓEIeJT,Y9 ҙTk׉EM32m@EgejleݝKf- #_@SQ䫡} _ uKC'(*-8nehR\ev0㢢y(/9֮_@ߤ D9,y3[!y`B0+ ?iHI81D*  xfr/ʹ\@eޠÆ[6볗R0yXזP R)#Myh=0&mY9n& ht_lŮQpGv!\.N-k``aI5hzf4~l(p;t@9"F:CY5bƱ]$f1N2(E˄= Ѣ~ ~@vkX9Z]?33!3IF5I}6MvE@ٷ N.+(mF^plTFƛs_n@޻P. &)9o?\jQӝ+F?%O&b'LKjj=嶬93)Lfga K\=YL3  P{i|_d3>'wtK K+a2I qhBDkROV +z?rf" ӑ]a!f㵄# "҉,hN0$"Ԙʉ+i1j>:b &8"U eM^ `Q#!ٽD#{$~ieT=h:1=V'(MQM}-Pջ)pU^dHx`EWi؃7ePgF _ KAO)J2Ȱ Uڎ `6O$(&w1ޮn|!gFW4Rav㖋&]eٷ|J&DKJ1@83 Ӆ$O uMvHg-rfo=:= շ7)h"<,qD e]ٞ3psw;kJA,pNWe:?#J L]zCV&\N>@.'bh,ֵC5exVBDݝAd"S nڇG 9L\l9U+t)} GuJ^>"bGǓEHEa2;&d[E!#qwBߗ1p_"7!lJ =`[6jY &ۏ<̨njt쭸EF_JE' @-?IpzeZQ"e IQTLqsOoʉ{kI؍2}wMr.,ɱVF̉ k]Z jn~O+WPsM,t60ֈ[)ʽT?$rF[c/a`'@HC-UT _Fl*? Z)>A &*VLmtTUWo7 6U[ڊ_7qp2-,q J9{S{ew3JCmrHM4֦n?Ѭ}N,[/ Kd/s5BDq۰ʂVZrw)# a?PLE N qƊ05Y0֠5m˪kܷVU߭f^/-7Q|ۜD޷^C+}.n``CZT&<-晱Ls>o5;z ,Bb[je Ä9 lrKK)3n*// U Y"dK40UVg-uKʝ۝XxGMY 噴$F?J=*qM'P'/> YB*[^v:DzǵlWg&UjHb-Gw iųIBs&V` ޅ/~_GF+\oh ;T_,Τ,lp^ܺ3v mM.=*V#e?VmrJQ С.;U[;hj5V]mK˖{S֑D܃GQ2HsJ=Dg%:)NmEqLJ8[cfLfN׃'wUrr M LR=A@JWpʼzExLq0ݒa*v>jRK:͖Gmy3b姠Iպtb'i6f 6jLI%S-H HCz'űn4UP@i(N>-UO0$Oˣṋ.[)c't yJy w,W:EjN?RXP#U+Gt UI#PF14--?#{60ۓ x^ɶ4ِ jRfW!ZCP5diހ?UZꢝJ'W -Z{Yɧf&!eF" kׯ[hXi ZlY$ݪ2*x/5B9UwG?ZA/[h-Kq47pD]8M?Ozj. MK_;#YJx4Z(fK$lQ}+);]X۶6(~3L65T<`9^H!Y,  ?9&۩jINv_MЉ8J `=[wy1pLRbW5h> qFnښk5[F7j ~!QA# \*i0?S,>h mQzB RE6 4Q:U+*MB 'lG+HmK_XSNh<ߢRX-\: kcylb؂cB2Q]!Y63.mmE |"[B@_lYB rxrLoC3:9y* ĆM g~ڹ)hxpזk uh_³}!k;Zw ܽ|ZZ&<%vꤏ/f^LN}+>AhWpv=͍;9uvNg;R_ӇfBeb7~cS{7?"}|쳋±i;r54kB6-!x&Qx?-t^+4b_j*&ަ~|_ a9NserN{Űb0'^_{YsVas|(dqVdhicn-b.tw=H݅1%|H c,NtX'y|pӰVy#P_cj)WV "7<8ó3( ŷ1^T 6 JfRd*@sq;2v:KMR#phԑzCg-BW5ʶfw5Gˤ")TA5H" D iǡlOkBG+J\!m?62 *Z`T3t5ͤ=S\l}2`rO#?6>I 9kbx¿xg4"lL@e@(?ȫ]'5d<>/vƕv2\lyqT0D).492ctEre|Js?MYeztjFB&W/:ʼnň+4L c'}%Xչf45onl7L'bN^E[V05Ib&瘃YE*t}wpΖAкm"nD_rkpG;}QVߐ' J':#-SLG[_kwId`nuX$Fء"@_Z38A*k?]6h؜vEHwX0Ks+WK0j‘dT/fy{=$ l n[p5F(\L.rل^W!`䍶5iOVtgEj vt7]kn! )_Hr2gUXf`;)S+ˀ*vr "fxϦ,I3U/ \sRSWRKbXz  0|X"i-Rm fj{_E@A3DH/ g3ls S]]$gcOASfۺ_(UXE)P g5Ok&tˈ{fnJՏj}`P{x['%ZSﮏ>Vk[kvr|$g;!3,ğ׋Y!m`C[o@GyqdA1U+`'Z1K"W?pT_99v׌D>P(sR)U=PqɒM Kn+'b< ##q 6PN&d)>fd0 201q}юE5cc{Z|7Uɬ::ls&ӥMg?ۼKkA(p-6u^`k?~aYUm|l_tҏ-i|~5:4F^҅œ"`X1#yмr +)r*bF~Q kB18xpzVvu䙡TSX`JڪU/ ޟ`0yfPk؍K+ռꖳY/aܺ wU7G@oꀮ@Yrd]㭭{r"aÅ]k~Zىe֮#,QtΠRBd wU3t ^DSe%T!,R&wV>{zsߩj-3|!vT`_ʕÆ"Spd>k a8Wqi4SdTǏ@:rx5 O)j@nN*}{ LBZU(ZozdA.AFD;3ΐtJ)?4fΚA$I~NNP0'Y[ET(X\$J\o ZzB9ȰwMݞLo݊V kS ~GxX/xLmۈ4Z70ʖkf`]@k9:ǒ$zU敔W y4NֳsYj?`Ӫ[ڮ '[IdC]*ᜩNlrz-޴ef6W8T?"(ڛ1zDJU~_? Ja=u l01Y{Ǧ}PS=n LG iEOLҘ_2,pqo2;_Z'.c3Ǣ8J-` ]ؖH7d~W{H`Ӈ|"zM7v‹(pevՆNB4O2\"έ݅!':7c%1դ8Xg.G&G1B|p"y5iR##4's76_,(>Pj¬F8d.{qkrYrWi=Hv)f1XiQ a~m/3~x-86Thc6$voRqQj L38d2,FrhK?;?"X1G¡&k "Fܳèl0&=^R *ۆd2=DlLT[bNp$ؽ+D04*y)f2Pv@Ꞝą&En{@v yE%٫qd(իۙyŽWH# +`/ Wǜt-6?^|UnnmF<3NI4 .x/f$2_fUO d[:`hUt/5Bwo=0}Pq(tQwM".@ &#~JN\u*pq~P˵Y·ym p?%ez0SOmXAJ^$Zqlq{>Cwuk)J`1r2Ql $މd"j*f[7xuT nȪub2bdwAk4=4E;` uy3bֳtLur'7(lY%9%TPiJ6n2MabSfz=qK.p}g ^;UyfpYT#"ըojn߈cI3|R,knTpo}O{HZ'>H6 v:r`Urtl;KH|{ Ino5UR'#&ן-ssd)8}zqJ:َZ-?J K,ht|]# 1S0ْ7Q(Rz04 n0!<) 4\fV:c[0UƨkߒQ54DMN:qWAR 4CcS%k'KCH%68lUƆ}@+m>OEsQa_MDXa&O# ҴSਭiH m@а.` 0+v5xR )0HoOqitW<`7܁6L}2( ۡ-?3p(b^b;r?iTJCS]ooG6q<ۑ`. {,oU1brPnMKcԽ#"GVV^f88Y[x̨LӴz)$w2|ڂ3OHkQ܏ Kȫ0].G34lxe]S*9tn-i?ڻ\tX?@y/E3[B 'U"*%ԕgf, ,Ő+OB%>8\v(g=ֲ ¹r8e~C.r48ЏGS!(}^coUDQv8^ؠ5->}Cl͌rE;J`qlQ+^%UϸY+$۩3ZF*iw)#_u6 )n>zϡEY(R ʶBwl*!\@>U2|A}[bAD]??* -̹yPlb ƕlUg @imk!MhtQ:wꕴFuvn Mаbޠ2ڜ)=1e6fx;o QubCq L.E$I.1Ԫ @%Orf0Wi&-niH M.MKg#⢭=D8"?ݨ#uN]%BfER$9"U JnҼ"\.A16x'hʣq˹!'|k՜azck~LYd1;BrF ] #lmYJQG\4}#>lpcjⅺQ yIm %UzzZr6ta&@NMHPc|ޜ?Q焎&(&R2xg7Q4Oy -}ʓ )vFfX K"JDelIq6Z:7MmZ>HMAWms8Xjv2K$ 0QMh}{nxB:IH']?R5o(5YvMHz.7-%@}gE}'Q}>|I_B٩&ՔQAMm: qk_!5+F3[O<pAZY{F h͐G#hwS?f7DM!U +rFPۜh+^$V'M*ylz)6rO3dqc]=gRߥ`i[ogLEgh*jɼ kzUpA0c| ׍ ;cɝT2.A5JKr7.NM̺rqq^ݤҫ2\4"wc!!2A:l|mzZH'\vyn. NB.ǎam{ߧUdh?4yJ^-2ߢpY"koל{U`e' Q}WRgnY*E'c%^׍3-ax;kN,1gѤvuGAc:bDC \gѤHl|e `&S)t-T$F&XhlfX <¬R)]%? 2tQĢK3hOA( I0WX췦e$+XXBW!: ǗHK[meCRvLco˻tRfiSЀox;8| i 6s3b{mgtGvaOIr2^0wx>IPHN/a ;Y.6nø%t]GG=?t@ؚe_Nݰˇ;_S)ms;f3 9w "o3SSjFy= J+7b20Kb u!FFKs_9GPEslЙ#{0Sh@{۩V"NӿmJɔN9gSdԾ.2\9uZ%; \ ut$ XgZ ^*|\τ̉w,.1ξDOF^{VG\3{!͚0}{ŸK:_o&lKWۊhJt w+O%gݫebm z=6.) 0{a'z+?4\NG8|}GSrA\xU u]89`.uj`w,[ć8:J,/v$?6=FK鲺0h-u`l>qt8NA9 $yAޟN#`:J"bVǾHT ʰTR_}`}5:f&MiÒ%o hJMll"sپ/)35sLDp`z\g}"_~w|EGJy; %Tcr.ebڢ倳EŻ/BɨzJX#pm3N%شUR 8SMBp;baAG!)Ma%WN*SƲO?EҵB~h7:zte75ԩPB"+!^ X.&dYT<.XCĜU'4H$Z1ƴZn4X) ay4}wvi}8a6 *BP'`2gkI|^k+ ^ 6 y~"Cq%S4 NLRH䶿렔?It]ֶ 9hQ[R4QK\"ءԇUwTƴ1PJ^̼<֙7+˚(>`tԧψ? &rku'5x54Pײz]~?XJx7Dpguڕ ŷ;YwA)VN'?+L@D~6hq>9|<Mes?;/ >)l+6=H;@fzԾOe =S>ҽ=G@_IN7m['o~0oX W!(Ē=FSā'wb߻'4E -x <vx-5jCE,Zy 09M3unw;#xd 7pG瘞@K ~!ޓ5 2ŨwΗW'++c5d '@o2/GP9!LsxI*)}셔ڣyё}H'fif5"| }<~Nt4@K x+1Xj0:DV8#2@)E`@ϬJsȪ7d=I։e1;;&иzXc^9!h  {iMhZQ E(;ZÁyEXc}nR=Z7"1d+w -O)|k.N\Z7/ec<4+:;iJg. N wOX34 {VNt'$P)̮+v*-fgI6||4O7rǬa.Óc Z^h(08 _#"LkI%3|_SFպ]Ƭ8as+ b;ub?NB$A[/ m>]! py㕏, ShⳒ_jFmnnh)w=6r8 P3zjc-qS Iij||q(0*ȒS%]2RH) G6 d !s`a 㨀(( gr(f 6=_n@i@IJqob6*G~s:۟Ǜ<.G޸z}zB ^ zH+ I=Z>WPn |ZQ3W D_aPiŏo9i}:JtR=JVGB[Co?DWпEtf}i BfD%PF.I%T\L >N74/tڑL4ۘ ;#cVe`&2!pBo[n;!tc$*"vjvP"OQ@FHݺxev&Sc(wu!RAPuMBg=EjxKPZƆ Ip.Kr~ B5\W؀xfCTNUJ窽W_vEJi۔ecr.B_#EjV͐LcTVcU~_<>\>KJ?n]RRs9~^eߧU֩w^g*t +܊w5m!.4־mćuguôYE] `pB%/@2^&FsR+y/^rn`\=Ё l l\Xk+UIꭠ?ϮBQ|V M0c*P`7ڲ֒@;~>CeҏyQ*`&w.BGTLM1$V2;PFzMx <4]^1nV=} eM02>%ۙ\kd;V+DЏg:4$˥Y%;BWMF!WCUH?v:[ڠ$P7*1, V,@''0U MjQ^P=lXl@_T/r*j1W,A֜堽 DIG0+J"ְw-̢ڙ-)*!S;"na+,ݿ j4t!jeHŀ.$JL4KYh,Q?R_V($Q,` 7K,o]=|ȎG;_ 틡}<"}β{#}wY;C\7Ɩ ~ȿ5QzYo:(ZBPmGSJpQJt#OP& 3:Уa@Rhl-#XIn\dtnC&cL`LD*f2ٹ-E}ː W)QЄl6j#b xIj ٴ>|0d5qyP 1U;ɦVG'gnJ(`,&4hsYW*i !8[{H0Z()LQ2sTcu}_i]]]]U f'>K{-Í]ߖFD(7uakD֢Edzg5a8yVaqe-;Cʟ`)y>I ~OA^8xE=,VO2p$_奊-8| ٿ<{XnK..+22x!ZoӜD).: :!s3sdpHhU|j4u:!s&IZ u(˛G- X+dm@sT`?acbW(*8/w-SfjjxtUj<e{~Ji); 7&9_#r1b%}j4Mfӕ_О@Ǎ!ܤާdbhr1˘v|bLo"V@I@b/wfw̨_,=.'^g~ݨ0~K rߴ@s`#J;ʀarze¬;)W|:]ōSqg=^v6&iR)30s ?`shlM$Gٓ:&kԯWV fs~=Y4S~j nL㽕|@Z]Q7zgaR NYOP{>8l3qҴ\W4 R"Gr:Wy[~}; ,nţDF2Ο҅@uA;Y2B9rǩ zRz} ' U3-P!,R?˥l1Ji&+y#XspDa,`Oʑy8 h6'q-n[dA 2ޙզ<W|,~Eugʛ_0lPq,/H(ćUahbxb$Ah|lO)xgź&Ipo.x 7BtMXH絊 \Q\\wmJ$dqC$ uSePAؾg3fJ}^zr#C;-3mC&^1UB"r0˙W0potqak?Y4nJC 6i;|xka;3:z΢9G:"pz%MPRd^ExE?ç[7]_MOTmktN{%HiWޒM25%1QL1Oga#w)[B#Rk܈u8~]<#0\id -%@ax2/|$S; 5Ͳ9ySWfw9d3 7g¢X&%_J.9"YSi<=X7(<Zq} t@(Khi [`b`4ET4%̨|+μMNeAՂrBiD3V9aO+NE<$Ȁۥ˽?{/J6 d7LȔs9d,7btJ-UcZ.I%7w]OudJU %(fvNym'6xji~W}A3]oJ&C$A v G\Zޙvd&W56U%F`t(iYYkuxiRHrI,Q2 7cJ굩,tUL0p.!5ޯ-*t05Kjccj#,[G`^FU͓A5?;(:d:, |nVlN$M_ _xqc䀬V.$L=JKPy{f8|:o|8OIĔ@ېaZR8q #kk ~.ɚीФoCҏiݨ2:4?f`Jm 7QVxX1"Ɍ&3PyлͥD՜4n&SIRD[ē施~ HNAߖ$U&` ϙ39WqGmۈ1۠tMȃxz1.@ZIa0@|2a& ^R.@΁CRWT(Żusd=8 k m]Hߑsj7 ׺*+Yvy4::Z90bٕ62v4Մ\] ӳ԰j* z%T=- yx.xݏP]M[q HeMOf&[]/tfh;E;\rh>t%xK"Ju6X.%P2o_0P@Avϵ\' *k@ȹ5Om q5:;ȿ6h31l#EI3qGx|E0`Ox2ᰁص_ "13Zd"MkzY*Dh Če_5Ms~68+s^ns!V2 niq!DvDKŞ_So[JPzQAC # #G)<40v,^OֿnoU5b f1<=ڊmnH~ 3J!GmtLT*-v`"6!RȄy%Im/g88&FcM@ĕu(p ^z_.on6U_?c: 6q!rΓ/^3zTe<&}|3oyu ,t]H f* «ăڙ=p) ݋ Qȹ%'0FF?2BæM7)-^g'XbZH3QR}8|42GIWWS_pAsV`}`γB?v3!xyrLM.W4.r@zIZ>tɍ| Z wf*h ;nXr9Ntֿ*wg=v(ʝ 9EpSh a#Nڦu_B*J/]'bzDaUB'GЍE6;ͷx΀8m4;^Uبi%]!}3Mi! ͚6]ZuI-l79~&jdϡpZ2_~cu+1]( W`;嶑> ai/buS6^ ^~η`Z;Z DZ4V`SWlѣT+_ s!5oKhY,ƇvMk)h9iKbl ]L⴮nu_3+8jːus~4C] b;(@gT(L2K3<6V^#ήpa ;WcӺ\M#&ZHJ @]^?oqqAgVT,~q{0֮WthZ)rUNwfÊ%NH}|Eed" mrz^Ў6~J!1%;T$kdT39>jF} z"Be WP޿sْ#Ɉ@XUq%nIn?aJ} Sh= LJO>Ww#uf-V6DF+a.";>!U5ƶ#p-\0R t:F>3Dۄa /@$/lV[˜ۯ:j_ODž$JY7SL"gHW܊LK}6y$foEK.ܾ!|= g3O`*OQuP҅CC1XLEYrQyW]l ,i-bgxF4(TvZ?i_Il}682=ZGKX yf"i*{ b\8/ 6=7dJ;)s٠jGo#,$D,~rGo!{B]mIGvJ##qU/QL$$ !m,f`$mIԈw\5N\̼"*/g 5Ttm iJR{ # G ſEdpر_1r!ҼTt7 Vnĺ-@,ȾdC:{tF2iS *aJ@K&O9rvj:+DKK']4㽹.ƅ nB~/ґ,#N|K2LBc}\8YOsBLy}J^~BӂP7N!KORk-c?[f` /Ә~=BYCm䘼'ܒ^Һ1W2S .K 0GǸ.u (;4PPC'1vF-gm>saFlMȣfذ3կtBL(:I[8FFoZP<++ۀr;kwVeu "L=}W2¡ctʛ.act Vby2:/\vQ#4-[  O3}d%aptP6F/JScAҷtө[ Q P[+3 E+f:)usD~?L;皅ËgCg"旂 T/?i 6sDP* +r'DM'BXj! 4+٧Ȫ Yim0 # =w&yfǓZ-psXwq4~&@AFwdI_ eU1Enu:# [\1NĜKe:@9g #Wb>{ji/Ku1I]m`Z.K~#Z;F=`]֒ tjො/xg#|>4<+PaƼ_MM[L,5%Li1qvѨ>Pngrg"̳Ņ4_TSM VhՇՀy_uFS8ʨ+Ml G+ թVl`O!3|+3\yގ>gܑs'R` f3f]6ݔ/ux z-[]04Xar{4qb:9gE^u4P!XRiE9h_wwO~OWI݋'==~M>ߓY~'|>w_=;;'_;I|=τx_gknyzs ߓO|'1GuR^K[W/;5z9/rKLYNyH0̭CXn0yshވ"u Zb='PUdF" 6v0^7^Vy%0PRwԖJg$g~3A bn4&^2W[pg;p'Av@YebgL>4{b&JFKgMTSN|R]2m/fzqcSPZH'Eyb7X>h=7Λ7ydmyJ~-FYճa^FoiRlُZs刚5k?J| & xKH5H[ '/ӂ ;jc굩UAe0ue^E3=ױ~}JFb[>lCw.:5%$='|%˔ֵ4x 6!D^@$]+??ԗWLlE+ժ&MQzҪI-hF4΃[M9P~-1t_/-e kw3i=_AU=bf q["@M]k yMLuMM|&%#s{Nq5Tr!Fd5I7~|s}< >?&[ȌdOxL@]Eٮ$S+e3b.Xc ~8xgO-& L!=e|kPKN+Xhso%FG˝ᄑcz\ͰВ3 "[&5?Tws,.\bw/8a`IRt.C  gP{Ob.IǕb)|nN"5f~7e֬y?"5"M"cak=.$޳m"u wS5EˉO'9fZwpլ9Ԝ71h*b CРdbxCxϯ!tbCygr %0Q % }X2Po#"!T.c\^x(rnXAiշAkXJ3~7xh/L|e]:`emdr\U['o^IJ {B x] mf> /ht̲o%='X~qB`@+2Gߋ#C`DW2嶹FǾ g oQ8M1,WB+Pt hyR0΃~dfiT65]Zn({.Ԕba Ro|of $XdIvdǟuIĬI~M b\Ge8۠Q0Л2]:@<ưA\ʟKR7k+wigG]p-TjZpLA_Ո0gj8Bԯ"%g?F ՘[?(~#Frii:}H*-[ZVZ{B7:L sbgwa.h\ [C]C(y!8az٩_q % N35)[ܻ A IۗI)O;]Q(r:\Ӗy'oB,Ͽd<ڤ,ub$ޓ#nkmo{ɗe+qIwRk,Jns.oacK) ]UlGgU-m4<֔/EL xJ2?"ᐃ_rD,~0`^FD _,› q 3Kthhcկ_"!޵  7}&4]U\11r߯S=b`,@_6$[[%֟k:F•lb957Ta)hMe; mfMf}uaNKiA,N[oWUZ8Uv> Tb{o*G::|wgG;J|lb _׫Jjɣ^ `1n3#;15&Y甬QC yLeT"|lEs&ϫ>W~/O_'Ơ>(̎NlU-5&P. P Xie?b)ViTrR|_US^;[B C[ie@).]B?ڥPݶRu MH/r(*_yH҄-DR1<2ȹ>XNcǏeE1@.JB!;.8p|EUuR1@ l.ЏtXrh4,Ѳgr(Lo%:ϸKg8n4nZLIWR5aB齎mC^4M9' h5kfGwZkD&[֝ZTSt:|BۑVG "܄FfJfrŎWetg?;:<3eLe8jdNT FE39L?e-Xb#d# ]8fxQ,:jN\ ՓޥӈO= ,-Tե\H#2:DO2ȗ:Dj+`D^6~m9gїꃷQ[35=F\-׎U&3O!N-*v)>%vNe|hN3L{]4`7w{^#uȚ "LMXB*ZoHC@rC]|p;:^P.X…u0a }(Ac>ɤ`AMG9 $W!`-Ra@wo de3tRͨZ[#"z'#S $w9DJRYə@}I Ym\%* ZZ* Xp?'sa+HrcO*nz|1G^ Xǹd[l_i7OܿI |'#4ꇭ_{\d9)( oBod)9-)Kд7CU$ z UzzԔCĸ'uط,T G%%P\Ot\+qOAGQ-u-D@ȝ4xQ p9ebNI';VwbwX)I N0-o4:/'4Nݜm iI]ux dm pYԼW*x`s9͇MzU+ 4xP= 9 I cHG{gm!-)*F&b/7UYǛ,,KR'q0my5hHEAxM!] Bo) r; 5w2BRN ,sJNyd0Q9Mݿo"+AVKKk8M /+'Ii=p܀[=kp4-+}f> ^!;=Ijwpl1K.t9y5LYnsŝ/0?T鿚QmXb4hcM_N0,slCT.]wH3d[OYQWEAIw.ziVnj1bL\F‚c% 3ft'n@czF)8t7h# wp5`ƷS{::ye BђTmV[զTgc$DɎ7/g Z[u3CϨ/9p- [tfQ~v5E'" Wb Uw;3jko=:_=`P7PϏ/x)RdsH'{E)M0h?2:_{)^98sKo˘2bE|ePZ3}g7|s{TP 3$Dn[S붴wXo9hObTbӐxt!MXޜF}i1gx^×fAro~RZW Bαݩ*1Nfqa|8KIt_. cYD],(4(5_o˄L@Pl@m3\BJ5(βOŗtlxiv&'ǐRwӛf68ߓk3!iI4|f)r^/1s!)\d6uoA| DZ:1LqW)#)"Nz%|B' Aӟey6$LE~+4 k 27@N"3 #?&ېy<*N+OuAp>?fc;Lrg DºSTk"@=YeX)+O6O76n2 W%Ke#Z.`YyZL0۠@ޠMȑErRHEHɸ2ݧ5E>[FuPi]^[=r|jI1;U_/~EunI&#+励S:qC? 5 / FW^,>ʮԑl}/w=CG0 /wu(bz֕ts?"N.$w.Y3JqIgt NM[N l"bkAU1@q!t19.Q06f`}śo$d 8T>uEK6PZaQn6QUzj:ssܤBh+S.f,. QLVnZzL\PG*>_nO}հqR <c, .aJ4yi71G>lxfñ;+Oip1JѤ+bX8ƭhї vPHB+*H[C,jRZޫSHS=MWsBI'dUI@.'7ڰ$"O*Uc(f0A+yi3mŲWkA`4oj"&|<a驶/wV{]`fI$~Gk fPUW;0G=yq:iu? Y2]7{]*ELBԓV@,^8 [&D ʑI)[tIEfJZH膟fP3͆D) b't' G(>/J$!JI>6.OnGhXi`"VD~v@~3m $W(I0Y4c)^FjF6EXI]>^96џ {ĴaݭZB>ۻѻΦ1x'mOvр4CE<:Rcʪg%m[4=igO*P:oNF;R..aʕzEO>Uz;#1=`:ʘ. Fk LZ(" Z2LLȱixYv998Yȗ4 }l،&1\܈1aU5 n`4k*Sg]j}וrF1w+G>;3O*MԻ^7&F7GipEY6uZx/{=7O8$zƉ!bj5~e bW9@/{ߦDAky9EҦ: 4‡E ''xF#Τ0{)EaެuBK!xJ٢@p6 !Zouaø N7˛$VvQt9ҡH=?/78' ꎒYρV?]O+/կmH8E/<-uV>Luq6CbV4a3a!)Bz ԬT5دQ^ţh fyf7 ФO ܯliCP6,՞ L/~»|vlZ%o[75boOE3Y2|8MM ^eDR|\+@mZ’û:L3$HTmX3R3t'*H.kT}$ɠX`_If 1ϵ)`B"ئ$ňz&4n83 ˠWk'Gvя/ѭ:?b?\}Tf\cu.a]1Movlook8Lhmvߜw6j 2 !@ςNVF%C/`vL@}?T oc(Ha*$NPifSJK'xkWQCG7Pn#TYZpe^qtpD2 %ˮP( ,\R΍s U?lFr<".tV :CU@1kt>#4i2S"U17ĢpAy)̙Q)_jp{M߿t#.[T>&֦3]o&x}X'i!0Cs,{[3/;C#9||S0Cf֧M/<xEl~s ~-#$ [<]f W3||ď\Wybjힲ L )P"A8Ze0 8 =Ǣ}l"S,ǍNB)"gWSo'&}4 v 's)Dck~# ؉k^+s2ײV$*ז=8CNW>HL,11k{)&+IcF1Қ_ 1p렭*]t8L3'oN!ؾN  ֛I9md eixJ4>r0 .}M`dxZ:F7((^^ؾWg;i(\8۰C͑oKPѐCJ' (u@ ,bZ)zIyh1U9`U@%t?#&g"Mnb\GI,Z")4p;&|vxvĜN+]#H۷jРDH+x9$1|iD\id;tǠ(gXߗ/Wz쩱1}aڋQ+qsl}œk ҂=٫O<>p=!IDj˳[MZ& %0WET罧a'ڝ3:a[*Y-PwAFof/j1c:4y-;Oe[%("üu0P*SBH~OIj=%+МJoX_=dxxSIH1Y`~`H?; O-Ae3Feަ< @+3RәF\,|ƭ쁁{~cIKq&x wY6xƪ|rf L"lWᩭksXyaxϙp~ b2uc=K"^X ЀԼoUƝ_il7 C5Qm`QBkRE >Ǎ |w fGLGaxw7F6@Bk4{큛TPՕ{"o"UZ \Z!Ky S_Q5x^GL\ͼ&> R$F{Ò+Y:NDКy;nM-&˰/W;Y8zz19-X ą.ٶe򯬦.mZe"hDԊ[5"%LԸ :N[ku\G1q#{ݝ`Jl-̚eqs= {\='+kGx8:"t'k6WmyRD1 pM!~y]VGwviDI݊=q@lQMN2{}r-f41^[0_p-y;ov)B>'#@49ۦ@>MA9l k.TITS)[V[J[1 jCƐx6sId`Ewv !* +a噁' 0 A8o:,{⚈~|9Ms9 cR]%߀oY%rR=|{nI|VTX"CLٿ$,Mohm,18 c8(m(8A?ˈZ',&FQ+0wA$ZԓZD_U )&튟ʴŸ0䃠@(ӌ ~6+O6D'&'LzÞDnw RAs-wqSz|ӹO/l&m>VI2XRO*}rHَ2$osmXu2-,rEG\Bq>T gGYCXŒګ-pgFRO{p߹e㯐LjEVV]?\yX l`4\ Z8G,K58:|= MI sp+[Gߝ  /.<9 S%e]yLE G~~1N_$KHbV4LYZϰ>9| D0DqJrX&vqh"DGP[={=ryr\H$xa|kvKc@~=SY5r?wGbQƧd'W :ZRx3BEU?b*bH7F\{G#Tx(&3V\2^~,0@3b`CL>;#( p  cج}C=j.S[A,6'+~?ΓYt;3r|Pτ|Ad"™^99˩en[ݨQ;Z\:7pIj½+3C*&#[gӞF ӊ(K=ڀynчR /DhLU<^x꾎+!o9pGA2ƍmK˳rAP< V?ܽ%0(G "jg&lJ5Z/-CA$\5]akҍdbx`VѲS#DZS*b`KHd׎(spU1Pq$ٔ£]W&=\iT8d!Q>+AIFi;OA >v,A2L y ~չƮW2Q`Eps@Ѻtl{zVq]whkRRq,1 G kONӛ[E";w݋ s I^l_ނ3-R'>tM䶁+]7DI0yd" 0\NR)Eߍߠ¾9/]|C}qAtOS`<JYcNϛcIkA%,P?$MZ/TJ ŊhVn+TaGfB^@Z۹opUyk`R {\b09?:?RjL8sn8=p3ߍC2.I~@E8[JqK̓9.aY98g1d CaYTBk<Susn" 0/lNuub-n;ߎ㫶eo> Wy9ã3u~ Xf-TICh׺7A)C~ތ#Yѕǝm :\qA߫=4KxcdV5n?Ѫ s%FcL"p:cs6Pb&6fc~;t;DHYOCফD?$Ǩ`R|?dy9*-w W:qrz B$/}u2l]c=}qa GPt9Ѷ',28Yiϛ]Se}\$:䌔~r-Dt3RhLm,FC ll|q0iKIv^jE>X+ ths$07&r3#֤ MӔ\,Z#[R?&/dQ.3F8hvx/2Pљg/1C+ɂVnU/Y.3X !lbH)BMTVíTW#VvQJ;ҤmAd, mݚi{J 'nFRK.Cb`!ˍnUK-䙀7YJ6G?%K~~!˺{c;1.(~Yى8|~Ycws3'^Z#)wk ;Ba]F:G#eTOmU9 Z#D ضS;+s"NZ:U&kcm|'?T#r+AY mZYO{ yLUV:]znմs'> Yָ UBGwTn7K>F1ŢPCz'*m|xS1c9.?GN03<xFpvm' fomo}<غdj#Wm ;CaoȄKLulisWj5L~QH{a 8ĆR # ֌Cql]yc"N%&+,'?96>&4R}a.j6@l8iKLW< #R&`AėRlVBN%A+u`FdlVUHN"wzg*mĒ3&TJ$TyO2j:i& OVAwzM5 `_J:cNմB_U_R[Re~E03hZww3.LJ^D(ztabNU͠tY5=Mŏk;vK(x~܍şQb*BŽ$L$8!ge_Eu`R%K<5dF[*Z^|ƌ&f" V ;x,L"2Q߆&2 2wP ZrPrs䄅!hrw\t>aS|UXHv-. T\[D%^$BTMj6@יwk)Bsӏ!F{oipZIx뉠[ |% nάGDd *qX_R|.qnl,PD gUx~¼I@-2WcNwjWHcJ!U\i 4{F]\Vt q}!E\9hфԾ={*1 h5r"0QݸDL2<- :s.E}gq# PL,¯U3 B{Y:Ck1ӜXO(嶗k)МmKOSfrҎNj&>fRI&in>d8Kd"]6~| ]9UKM4L.x> }{!{_\%N8ml=}6=2<v/a2xsAd A1>F5r_f"w^$oUo{H>>W8 5xn>9z3rHI,2|=hS魨0d>rXpOW3cwpwvA;*nW/ .PQuD+@*?:}E: ~$8ݬէ9f{)5δRA^ [vhKe%s -fL"-iF gq>Ӏ'AX` utsU7(G߼>|> ] bǴ1XvhÈM/c=VZagJUk9ðdؘ]=Sя _}v> h$!Q.M$ױ8dmۏ7]KV@( m9i6>{x#.*bEWIbǦpS1ɪg}*C؅j:>^4lU37"{,qk5/q>n͍j?e hO:1ʑDPtE^Tr eh9 o>ӃPLqw:qR:OFtD 3PGW9b4>).(yIZu"U" #Ձֻ"Ƒ}dx 3W i]yOAwT"`g xg \P螻ljXE_ 1uX.FR!vTڱm쿳2Fw& pFE7{ў$*} <oCi_fIZ&5qQt]}t%&=C SLa@@kJEH(ɢDKJoҖɹ+ ) oՅ}|Zt?}@c/xO_8wE.5~Hue(}u7 (h2wl2{ͮ"h<ײ fT❄&X*\/.GO$[=;Cs>⑖fB 0xP2e]FS6/[|ދ;n?sQ Jf/@ B`- YҊASTTO9r!i” ׼bhZU^Eb T*, c&IqmElL /AQʎ~1 A6 9.a)c\0ڙnN E4|jAd~%3/ܙQ^:'P$n=aZ~{9YK lPt/)լNtYnDv#Jbl%N6K/̏ՀH?h&c=&jDs鿺l W /iNP~_ڹBcu]OM{g3}[lQP0 !LEQ9kL-o.ĘT.O,F_1Xj>"  5\e3r,=iE!5S?L\&33o4Cs\pƗ}0 z0YF@X acĿ{Rk~c($;3π*yMF㾰8C͡(*c7l@KZ§M}f zA|Eb/}*]6L`__*>vB"س~ z$^]@E4u-ĸ4q~P2 %K'S<.$m?( h!+uz7ғv柡wԣkMr)S $m .>~gg-*"îF\!OH3ӶQU*G8ӵG 4cL)=]Á uVv΋+N[H]T'kOi-K!:~&C:hjY&u8&bߌGL \$uk`0|1V J#A~n1ˆ+ܠJ^8";8-E5T{j˶Zf/JΪ;ZrGo64`jd·X)I?Nvf(^/3ܽlPs<ؚEo!e&autݙ:Tܶs#0n3m f>p$zq&GALǏfٔ”86 FG&%y6ZW) P. Q^Kl.+G ~F$Ik|Wv6v˙A/2SyG*l)Zܩ-0!5̢ݑTg h*t8bE{uvW_߇L޲!&hPhz&(Ek Ѓb"˗h溩 ӏ\U<4J(UbW766FTqEK~M`"֌drב8F@QG^?^VOR>׋9P 54tNjwg!AY0e<}mWr&`FUE)d]@`GSqXIFk{)[CSZd;)ɉXIt;qx$ksuMAt{P9Uehײ8FӋ8v92Bv2]5f5HxM+s;oPmj&!jwW4`3ő.s+3b&MS~h`Q8߭^Kt0un=P-,׬=2Lz7+fʹg[1/d(bn~ /4ĝXLӶ8oo0vH{{|GD|“L BLV<ȑ)tZ2`t0K_a= ۋ 2~Py T a^殲g;[VOkB<1淛8dKVMtKU / 1}*Tt4b_] ے;DOy :w< 5_xM>B[bj0n+c֔7I囎Cg ^HWEh5DBZ]{Ԡ'&|p `п߃e T} /7'yGQ<0e;k~1 #k29"rp=P ĞrZdn&+?|HX.RuP \ujqxYf,x~ܧ91 6ybBN㓎9ejW;%K1/ճL*;̀eEiYO)F+=(vMe؏JBz69otb$ T0$a ȟ[oNX>{oT`p#QnW~ `CAvO&؈ H4 Ȝzm#'\b\=rV&x^~(C]d`*&th_qی*JK"=@A EEcx ? !cu(s[/)y.afDbǺWmϰOM'[7#E٬ޣ:(!0B[1#<\ _P,% eK襾9&׹ʹ`5AN[K0'Hh(m6'J'%9~ap :plIo#r)X am1#@Q[ςRUg:2V(UF^lޓAOIu*sgP,lTŲƭlhTihLn."%er7+:SP~@_5L kCFw7^^N0$or9?蹼^`o$P{{;gˆ=)5ZTg +s݆sr{ا rn9bvNxr_-y6 4|#P[I:͠IQ"z;-J],l3igpDl\.aEy3 mI͗8U K9gwXj>1V }]1au>F Xxpү9rIԋfv2{-.~MUEᜤ_D{`B,ITY>bA3yvabĄ( a7U;hm:h%eHOV 003cGsFTgL W{:l.xw58A՛3JHʈ\o2ѡ;+R4uĹd-"M(RhثVr[!6ްxxU=?k N,oY`ylb;kE #"JSucptNPEe6Vg;!aamB:So z:Id#}HVrAgwWvl;yMʅ@Q9/nvS-cZGpnއ}/e6Xʵ+LbAo1Z+"B ?b.^#ÂmLQ/5ﱭSVadc:յ^&wA`VykrkŬ,ƹ, ?_.B>_g W<{OEVU7Haxar%UFgl9R .C$ >1v ;jWa*Ms sZ5NC⽫L.a5B玶hjF'LXtWF34J}mN4 n}W/x^7-LCe̯'~vu(+|3ٶPJV]E WbSd6۪HawvqˬbJKuQ Muʺ.F v6"ϏWD#n|x_NVGl>Rpjsp)5mOf&q0=yoɓ a߲B/"Katu+!׌/ %?Jxw*)w#ګmOV.hHm1^U\qyb\1taI9D8w4FT3TiSȀR[WJc:; R8:'jI=^c֢x{G|MuTtdf&X 8^÷m6b:梼4Ue0qfj*ӗ<׆ n␚7/#QZ hϡ_r`ej >BNS: 6>J=_pVUq͛XXސΦ++[=EQO .O) E=,mڒWUlS^}F 2-Rڊ$A k} \:AdGL,יo7]Ib+y4-1HQVDP|$zKS}l&X*K4a_bb0O|] brMԨƳ?2?lAnkFrOװ4 K&Xb0x?1Y`ٳ{w`atTDˑ/?dBș|23`$G1[]+>ω2 )x TU̅3=ϛ(rMMs6wnAKy;ЏW6 ?xFe&O8!" @ .¥u~NrJɡi Csw O ۶d#TQ&,fQT2j|v?, wdGZmݪi[!CʯiYb]qu~BC:ꡦfhK$=_ٝn to0CmwRFEѽ(SOK%="yfʀty,"Eu vpSG1~9ֺ?oA6G F)y#3ξ62(^:@!xr&lXDXbltPדui}Ƌ)R':=xx- /: 'c!k d lG0dw./TKR%'H,qOES&q+cβxd9zCy=$oh7v!z0ԩFiGxBnls:yȣ(V#[ hisN^Łg Hl&`,Suɗ*$YYֆ}[MꃷR7Uck(wp~}WAC3BS #}bcAxIA%*GI?PG G6"`@b)NrX}![lU͡@z|Qk,Dt~`JY nD.˔;,B|ȍ-wv*W|Vj b0 զ<#vج:ʰUV3 \pLJӪ v(猑ia.u#vkrY [4tT(٬Qz:r'48i}M(Yr$PoNQ 7If;t)_&퐁la%¨ J-)VJqG_8aPk^;Vk2B ֞S<c&[hG$Msjejh'  X0g\YV~_v:ڠ[.|jٚ?;>NӦ4pw'&ΎSWSRaۭU{J붙4Z9A]t/Mm!v g,qeCOL]X$(}Xqd[ފHŦAz)7CjeN@l,!yHJ[we*=IGrbeTBՖc63P;Z &[kB̙݉S̍.nrydnX7*/xd'IB.[?.QpX;nytMΔBt]=Ttw S PƢ<舤e[ 6o:dccv.^Lz66\ꭠ$AL-]AcQR_ x0QV΅?ZB-oeV0 :v&lQ%Ra4fE/ ď-5tOp"^{׌4TfNnnClz⌦FqPcd|&_#u^3wZYkߕjUWGk-rֆm. M@|4\<# &Y.$nٟ,Aq#HA"9%W&m91a#/@# tn&J#`>9S~k۽o XjtMw" =r];PJR ]snI]u׮~OlNW=z8@`\A +勝3˻7O#iC1> {-_ U^n8?Qp@^ #C I ", ̻G}QzżG >(4}~K,ԔneӚ>65lY [)*`D[ʬb UF,˥Oݜ#տ=oO >MȈ\X_lALFS7P)9Jsq^,C=dCcX.&;?-WѬQe[ S?zJpah'F[̕iRvCHp~Y%*PN9@z6_x?6mZt~5>ٍfM]%̜]NM=jj0l/pg6k5b5z'^*_=8UD ZiL%{޳fK/qdbjx1Xh,y!n#)0*qw" =$p8Ԥ#09)%A<ڿJ^ͭܠ4:Um|D s/"j9v-te)Gxm//////////; SE4\bx-pzsI4R3Nb2v6OGןq.jdXr+ slSy{L@Ojg ~(1 *TfBr,Rer^'QjnH˪pQ.l$le}ureыIIT)tjQ;:1qTxQ&c,Djk~/PJl#f'iZ -m\EZkaQ s"6[i){l1aWGZo/omVVe <[],wl{9D"^*5g)OM"/eHn+$bJ vK/Cq+hQ$Ė~[M*TZ,z֛ |[m l)29^1[M<=SiŠc,h@I 6QqQ$+2k0c2ِpՊku8:yZ:=T(3,XY H^h]{i:Dz ,>YEeP?K #Kq-?d _m >k 7e<[O#D t>Bc g"%ފ] ]<EDzud5>jrعub#}˘ 9SYhM;78G[:N46cX:EΡ+<)>p~rhiw7&۸G_8"߶0AL#HaAWd :Vk-P L.I*L?>1xّXy#r'_U|1DX\+HᜊB+8B֟E{׉:}ExF7pa5]p.|m[$@#s(45#8i/ 4]6a;9IBHL'}t2Xfjcɶx)`.Nv\/N%'&.A 3ƶa:h 붳ibA69`3aZE\g_26(W3r orLiQNU Ғ֢ U`{PQe5K0cDpSS*w,.i_ IѦVj\8'ǝ PH3-8E8fM6RZZZ}XB,wralˉj;ˎY&t(@+Pq4yvnn Q`?) =v\ X~síO|BP$ʮb-FfϏw+W{0B?;[^^Bbyz$[;vX*__p\'&?<*YO)_>D9%)^E-y3hj". /bIW 2b 0@C29F%CjamK*N ^3!j*E&CFvo7 |Ӫ!4şI4gf'gIzWdTϓN-\9wu|@:tX w`]:Ƀ2aׯ`5Zfi>(SB )CpqfRo;'Y'JrŦ|v =$Tt#֖';PͲTV]ͺ솑vXK|Ւ #];"|>!MB &J{RQͷ-$ @-.paw[[ܔQ#ҔZ&*ݶ$ą _4Ѭrha>jvMJd|% 0SVzhDSP%1-6Қ)N"U-AVKHWw@9tOa#wsR~Ƣr{=G'Iuj23M~E8]N:ԋ >`w0Z-X®K7,o{d!$RZRjGuP4>Dmc),G\?YVHc߫Ÿr1x?>dՠJ!J1,W ?Q*P,C?: Hi W] g,Q F7P O}.%vEM9-Cü`D}^ 3|/7(dJHow$i+0Mf}!qݔ mN/]`hÂ[uG cIHW/wn8~'}ۊNL3UUp\:el:Ў 績\ݔY\zQ9%#œ=VJq[ի4Ԙ2ta"r"Mn5j@X4{GJV!rtT.J{52Q#(djirLFFٓnIċ|y'9;M[6ζxq(+nj,ޒ&JrnvIɈY ^<Zؘ,-@@tE v,>ݛM"zϼ 4>d6Xxb qxj7@eayu)XAـ}']kBP^&c¿y Νfni^r (`h _3u¸ʝ$޶pt.oQ)U;ɘ[LbO{rtB6nHEw)SKx$"WpVH7"CuPJ8& K)nJL, N HOX9]^>tOk)LT3vx5=B]z;0P~FwMZ΄N|L6FV=B{3ZDM4A S 6-k]EZ>x$X†ZkU(9VípҙdbƒP0+5HRV<w9 gN3hA+S4.BI7zDhGM:'J4-bۭ7Gԙod>K}3Y8euI W4GG4Kh eW%ZŰ때K[;5@KrCbIDGw["k6Cآ$DCMf68B`8X9"X2kTOifk/m¸%:+IF xKC;";= 0. GۃWSU ߟL^~Ġ>"bfѴCrl/ڇI rDMUOEQMZH(4H+vo(A"ukPл6u" "FdFQ@L$ቴoa|h}V U ?Ӏ8-7eb2$¦RTWp#oXpƞFRj]p FM!־1co각QBX ֚A,M, vq;Ý0l(ήG$2mxSws^'u?M*P}.tD#iu C!׉Ch/"\9Xtt.W ,S;\yDL+ }~w5n[-ڍBq+9 P"í:tܤeӛg` }C3@}DM}{?c&6r!cy'Q)ơ8l@O+W}@oBҳSQ,u.,VpݦjU/u>4U|'vl%c=ҖkN#}e|^$\A:Z=~ew@jQL[߯Mbʼ _<ʉ~.h Nɟ)+zTw|`?PPj(5'οYFPzD37ބaҀX'-Tejle[ qRG%p3{ph{tI*+q^D`l$# 8d+鏎G;gt[|u5u3VF}mρFP"*N,}HGdjb͉eX5Y,$2A΄P/O. '*qUt6ÿ EsPPU~3d4QuԊW`02e^eỳb}̖kmZ +hLp}ZfÌKf2wNo'uJ, iCP3.5W34W)P*qC1R)ϋy)nVh:@K¼k̯`Р=XqlDC?}~I̯Fw A=YϡIzLr_Ma,]!m:Ryȇ[E]1aUomCrn #5Zow:RiBxx}J0?Qn-Zk2(^կxwfK$6{DFM",i8/ QR\|ݹ&<>]ݞv;v2,k i鮍,^qyeYϔYC#ބeiQ.q7Twe/qf޾:@L5b3}j EhڑH3ÔC(YDLV$PqEvTw!^GRTbYBEhZoR(f3$n=sǬZeWA +.{Z7%zrOP6wj.hw:YQ4TLfqH3>e$D=T4_}EMvx+/#)Gբez:a v!27lXw}tf q<BU/b5ۆw8q9}eD ]Wt>cb@p_'6J~g'zMUfoq#3yAi{d(c(dz0lD$es|Cbds̓9߉3ʞsWf5 oo(C6ɣ):k^xhh"xA|*{L55_0V~zx TR)iMcisB9 K3w]qΥr^o: ~0jdIJ5M y⤕&$n<lNVxZ &T7, ֋Z*Vk0-bbe7LSs(OxԞG"Ga ޷9&}30xˆb v]XM ,7;>uQyjIV\Y2 ? w+ 3N#I3.O# N/NH|ֳjt0h5"IaKH#DA'ߥ;=Yx[F|חy;;e>7j"4Z Wj >=Df(~nW% q[=$TN2RjJ$4SP0$ŀUHU;HMhCG1ܐMvt} -[ذ0wŵt= ~B`Pn!A޺?zﱁz:K1r Sju1W,Yq'I 0zjqE=tDK [g!piK<Ciin]N6?X3~3o/*VQ9k(Mp}X em|Yl"b9MU;F3qo'xL,P!ZOUjR='Hdx7RO#peSFb4߉JQ"jr|}4Ȓe8x{lB6CEjl7zHu?=OЉU1]Re%Yp W!JEp*/p LohW&yQT'{Y;A*pp+4inO7zQg-T1jt囹cN:|NԫT<)RGaZ~|9;1WkRF9%$ n"YW;J>sk^$RV,\#-;Ǿc$*:7AV4)@_vfqPnH͊%1 9CCۮ 4"c4T'A逦L S5y0U81 樄̟Ģnl هf?Lai0H)&l>5¯=+%Zݜ`{6Bj4XKѦ/OF=j<`g`I^eTM ZGE$ 18# Krƴn ‡^Cjg{*-;e[%ppDl\w %u 0? rmH~ӅEw]$NQlTz7<բǫvUi]4wT˖}]c8;d!.NڷRGliε'^R^U78H<\P @v|ז IGAue{Hw [i5|`*ν"aige@E5Syoe')>4 s%KwӞ, Z H#^)ZTàX*u+aMP]oQ)mCOGju`k)3E` #2^bԸ`bW}{+] "/XFSiQh 0'6%p8Vsod w_;'sj3qEŠeꯣFb7X[r` ;)vzWm*`^P{V d[jL >H`J3LN ]8RsDdO,15Ep'{Ӑ#0)y>PONO&f83323bfC.qDG1I~?kw24yס6q@bf1"Ddgq¡[QKN[҃WMAJNpIc `Ƈ.)YPĥ?5N\cOOR_yҀ H=8c Ж)^DÈN FhR^9P`|77XP jnVX+bXdZPţ08/*r ɮTMCHn&I+ ]? 鉵eyhts?Z?`'`;& Ɇ=#2:EMP2nIѣ/( a雇ѝVl)ŜU?5RU^~ƀ fΈW /!s-WG!JDv׺DPDCEǵvBZ %.=>GDw ?:ytYZw>J*jTf=4Efn"J&rvJBXȷПI gW^E,1v ;Kql g#SV ?E Ǟ 7qh.=gF_~hrVZwe 6.odzDZo#׼A-q&.O@=^h;CEVo M zb<3&4-y$,N+ «(t DD8uk3shi'cyBKEG[şF4ػi7'`$}W<&r(= YT`r ]~ƅat(Bǥu# x+ >4Y5nKWm:SFLߔgTqM$A- DZH}{>0Yt|){~N[=/FSC Q+w@#E$5K0!+hDJtzgomջfP<pȔr ~i]IHkH8-?W7e=Ie*[foj hfqs^rE{dSSDL$X%9b--W#S+ca55!9k L`]EP@h+0ɛ\RwaB[;DzrFu>{ u Ew֧lnrM!U b QGO}N~$֭nTѮ(.\>|mvU/ {3$Hި@5n?}{C;ԋϬ.en\3\x.QL,b Rk#̐s߱ф`m {`.EO :bB0+qr,7F dl~rvZB.8>JGꎉWKwO vUoHI HB!-N0S> _#pBS l("e>LhmH9@ \[H#@YB9 ϋc4yvh!zo%kw=!y6-$HMMo kӧzF :L44= rS{e)_GhevMWLK=ʸ͏F=h4e)j GT"7#i5.CyqZp|z5\0oޡ7L=iXhlV*8_1h~Y Gir3jKypMPxcjV}C(ːJ#m+!RqN]2q98Q^8{a,QhY,o#U#T]㥒F ѮvHc|jȏ&IWj+ўKV6s%D0Saos;ǩ5cezf|>vsFսAUB[L<}KIcdiQDZEmtSZPb7;zU{FzBox~\S }H\)F(4s{8Sʣ4Ҁ:IerL!f0Vɑۥ9-]2Җ"cVӇ؆jlmI$7+qR 5V+1`$TEBu3&)IXݳ^Ckp]JLlw>ƀb]AD^=4ֻ"7̞Q%sC}LUd {N&ԁ :6#W&}L%Ա]: HY?2;\q FTqiH&ZUq /{sXme?kZڌclx:p5Gߡ/~S0;aO0=5rc9Ƅ>TZa~TUUʓI ebTa))RT 5Q3=Il>&D躒z[ 9Q1Ȧ,vBD-1-4g,3$pαONo!WHҢ1=`G}ٍK7?`QO T4XNelKdN` >gV=2 ςuq#YkD(LGgfȆ|ocgUS)F ВѺln=@ ]S-@U{?(HWQ21=)q<%2!&L>2?`}Mߠ2w#Vlx#EIx=PUG,Wx_\K=DKl'XqXb7 ψEBwM bܓ>4Z,yRcЉ&=c6鷏>.#t= ]"eoNSzyb֦bOXیcxD.̻byMbAPÏ:KSga9ù/;GgUi=衑*JU$)gRo )q argk@ٔ 3>E=v2sOC/(Fd+71`!lF S! uTNӃ8cUaG{(/O {FnL|Z"Luf^yl(WwX *NKP g͠ʡTAF`Mk\(y(i>^ ?!!RX{g{pz}&Tr! ̜4YOa|Az2֨b3ʌzj$tmFL-b1|.+c%YHw^/Wч rrbEFs9*F.xbT5qjy;Yuǽl2I 'jȝi, lE%̰gtXYj+=9` $KѯƗ51o_}L:w%5PM$Co˅O5eD_ ֨}n{Ny~Z*nh~)BYG+Odm#0ժgۘL*$+Ӛd/9֘y@ޝ)Q.,G"|㘲b"*޸+1ކ9MaA!w#vĈڅAᰅ.sM6Cx E/ptWGe2<LbU0h77\[>GfP٭g Mk`M9V;QNG:jߩHuԇPBp䝨 $1,BE~U#ʺ\f8 <@x2Wd#iPpwa4UA3ǃ h _d+"\h=ūXqe~G!(C@ zյW vOmYh$xݔgx<|](XS ZEǁ KeDzQ,BnJz /\ ,aCA|[ꓫQx}܃pd_2.yY?98kF!WvTTT_sϬ 4' AcX'PA_繟镽fJ :$'<#{T@Yd| Y@)Ddm.ϧxT/ k=q@vOZ w%dI v#}spƒ8$Fn4^]U)]pٝ$WsIS컒<@{Yڀd3t*ɒy<7*NzkŢiǘ=15`)ʚ,R\ ;a(#C<u43Б! -o=k ^[Q"HE%5ӊe!- RLUox{wȚqD4b~ !k:lz1sɵV8_٩h ax.-_%SH".M={!yM<"9f6K*L ӝ(Y ضj4A󺎍H&4*"V%N7P[ԅ g\[OU{&ƪZnRa s ;v'1F潺۫T .b_W;U&Q7+YLB w̖ XSVT)˙O}OATz;#.xj'֎nOTSȵ Nr ָ04n96M zK`+ ː-sCOMI-mOorC\{U˿UNas"υxe)Hݟ/L>3S^386BGZAK^䒠ٱAcqL+XI }2Թ!V;ju>e7P\{ ._͕<>(9W{|2  ]2z J )쐮ZIiT`NJGlBj&SR-E@ vƪ춗% m$?eW9bjl0 퓎xaݵ! دMEd1ލ+7XT8z#SY^#JfA?ߕ(H[E{D1_7T.Eۭ3…'пU!;Lm>,,/[NAM!GĢr> kء\+5%cȶ: f\.2h$"A!ܾ{|t!D7<) -N79^EJM/E NlwV 7}7PHA̤uVdedXhЅ4bJ&ԎԮ/xF?oqLM*Ѕ Bs &_\^V7mPcD㏶5hAAH])|,6mFc2+rdRb,c$^u3M9sKnӸݠ/={-s"9! fƦH!N[aA,G聢A]v1en\Z;D-Y\pPl I<8g5(MjdIf^M_W !^=-3"Q/A&g6jX0AICu mJ;=F2,m[EyQv?N\ yRoG *TrRؖ9+wqZW?,D.1_?2eoɔo2+B$U`FDsVK3+PKS lTi㸇?ҍJF-?6tG:m* scP .idøS_k-Aܟ2f:K ƦO='Cpm8 M}yÚ U7\#YҤ[ Qt^|y/=ʠ[ⱘӪPpuۙ*F= ]Ž_M ˣ. yU^/<308,{ w1G['yX}< nQ6:;0|ƭy/QR!釩"*ju$Vϕ#Ǽ Z#,U-ve0){>y"O|' nl31gl[P\؂:]AmGЋSm)-9 h l877y( SMϭ;ҜָZpX:`E Q 3ٵ>3M_DTGb>޺;bXq`TH7"'j~DŽ: +ĶuQkdrŮi$|dyY8#ܾe/A7..7AAfVѢīVҳ@|C u ܞR[X]_Q'Ue5I~r1ۥDڄí@j \2^5@Ǖ)8H~7]xӇ+o:yTQGg%lZLG`?v ^T刣UpC&p傜UBB+n:K$=V݊v˩i[b\~w%dMؒ+`7<\~}ߋvjywiB!JOiB/Fo$̗@_b{b ڪg 5Ч#|LŒ2ᴧ3~Ys/s8y 9̝=LԂM½')Ӛ NV:W_Q(lN)Z?b"5uCq룗Yvi&ݒݮNVGe&jK,_lʇGS.z}CK+05$?&ǡϵyCmf7LǦi<_ASnDrb29{o"ݩRtu)[R9 N~+vL`JbKK QoxO٭|bRȫ&.ؠ^A#[V±D/k܃Q:iOh~v/ dI]θj@jf կŏ\dv棦O 6 %]v}e|zzOU;B\=c)?,0T=WjWgψBun;A*ySbn_X )B: <{N烦 Ѧ Rsg80 GN!,AvrwF;SW֮(qMy+;]⃻lJ#Y3͒j;.l-o#0+s"[VryodM :˚w'r:(ܻm8 $<6dHeA2Cm3Cܭx"< F?ZczrG1Գ/m)nd%W[fOZӴ6O8I/7 `s4WaP$qeUU$OMY:n7WIg p,7BXJiFO"~3 K&NLPMɬ*ֱ;lGa:^0gJu#l'G<ILQ>fT4^?0ApX)q#[<#l,rwGo/-PJBoUK/25I\]gzՙǣaNv`ISay}v[ K_;uI^4zˉ3Ʒ pYpX™q Ogܵpk=-վ,ZAw.8:1251>Y푽Pgqx?\&L 7Ex-73҇:(0v0#|afj8gd"}Xz pF0צ[yM6L,u)BUze>;8骜OSInQPɹ+>6m}j],:&ĶC>vZ}jp=չ?xk^K(d^ă ^reaZ @SyXKf{@:LtZ?=8,1xxZ]zpJEw'@"MK&C%aGnk֡ P8MЁ[otR{]Y)1\MQD(`|٦ 'چȨdTN6(YI/Aim&8 o۹$rCi>q F%sr/ir]n.IO+3CB']+h~#nfR_[R¥򋇖C*UY@N3f}3rCl&PL5W֐?*o~]7moG8 V~b$EΈ#e*1!}H9&:_wwk5ߓrw_=K~OOj:Ͻ[qDW|ߓ_ל n]﷿Z~~o~~A[ziWz1GB"GaAboojrd$ɤ$O1s9h 뼰HP}xΤ.gt(Zx,i',0Â#m^8?O|hEL~hؼ7l H,㝒#oZr@f_% `#lj%b+*Q[$6r̠no3(|&D/ Μn9tmqP`_ZP\6Fy1;n&)gT:u,[z/&>$U#a" f ce[{m !!YOGq ,N8f2=7 = L}o谄h. l*`YP2;-']iآW G嶴/C~YVNoA`ҵPҰz!A \wp7cLG9< #94DU_7r`88~_ح {C.}Q /y^M1 > IAK˙98֗a\gpfrV 2.@頛9_;7tK6WJL]kHXڡj x0.~*iX-S$Yڰ h'xÛF~%p䋵Uno=h-]Iz+XU\c$(*0"IVv[찄<<߸9fQBuĜCĸm ҜCX*lq!eRQ]/N L|q 'L|60%Cq@}JdFB?PC"#Eg1z5Pqu7l&'! e!B:bW'o^IJ {B x] mf> /ht̲o%='X~qB`@+2Gߋ#C`DW2嶹FǾ g oQ8M1,WB+Pt hyR0΃~dfiT65]Zn({.Ԕba Ro|of $XdIvdǟuIĬI~M b\Ge8۠Q0Л2]:@<ưA\ʟKR7k+wigG]p-TjZpLA_Ո0gj8Bԯ"%g?F ՘[?(~#Frii:}H*-[ZVZ{B7:L sbgwa.h\ [C]C(y!8az٩_q % N35)[ܻ A IۗI)O;]Q(r:\Ӗy'oB,Ͽdwl'Cq0"N8 wR>py1`-Ih׹&A_GzQX{A}n.%?{+i#/awv W~/O_'Ơ>(̎NlU-5&P. P Xie?b)ViTrR|_US^;[B C[ie@p0H)!hwbdS R2uC}1>D]%e7Gx~q11\Z^'`% >>GnJF'G Q>0hȀ+T؊`Y[٠+`E"@HjWU|fu" {yA?Pi<պoط+ Ƴg>}ic8)A4-AD7KmrSl;WmR:ѧ1wG0' #Ӧ7ṿGEުΏoib26<:s +H-\6 ͻj4EN }eI3 "xFeFcgҾMB . *%1_2B0Ŧ4oyc8KB(f#Q~h(-^α.Ƨ0( su8)(by<\=Q֯_~tG6e|<wTt۬9! ,aW_8\pD)*3gƙ/ KVnA5G#KTƶ`<, rJ.rXBEY&1/Υ,>WR5aB齎mC^4M9' h5kfGwZkD&[֝ZTSt:|BۑVG "܄FfJfrŎWetg?;:<3eLe8jdNT FE39L?e-Xb#d# ]8fxQ,:jN\ ՓޥӈO= ,-Tե\H#2:DO2ȗ:Dj+`D^6~m9gїꃷQ[35=F\-׎U&3O!N-*v)>%vNe|hN3L{]4`7w{^#uȚ "LMXB*ZoHC@rC]|p;:^P.X…u0a }(Ac>ɤ`AMG9 $W!`-Ra@wo de3tRͨZ[#"z'#S $w9DJRYə@}I Ym\%* ZZ* Xp?'sa+HrcO*nz|1G^ Xǹd[l_i7OܿI |'#4ꇭ_{\d9)( oBod)9-)Kд7CU$ z UzzԔCĸ'uط,T G%%P\Ot\+qOAGQ-u-D@ȝ4xQ p9ebNI';VwbwX)I N0-o4:/'4Nݜm iI]ux dm pYԼW*x`s9͇MzU+ 4xP= 9 I cHG{gm!-)*F&b/7UYǛ,,KR'q0my5hHEAxM!] Bo) r; 5w2BRN ,sJNyd0Q9Mݿo"+AVKKk8M /+'I*ʑx>: {(pL1ld9Cr7JQ^ KqO׍*,ތz*QNd vm05ul X{ eQMR\$8eYq52ߟ!3S.]N.xwC=ukz]srn͇wJu '[eR :eçOz3N}؉8~Z_nQV9=cig-?" Wb Uw;AD(%zY @!cKGJ Kwlf39GӲCޟ3G>WKl4l"sI6p$VqX?}.*^*yQDzY}?itYG"kU6뇴C>4A 42T{+uQz-O{Ak9qg"BX-Pjd&4 G*1d.ת{qBb۳P|ר%,S?H ZL<1.Qa@/^WD;8b*L@(u5h)攠bzMp-@U vL1"Kb4 sÜ̹mDA|YP61E6@j`:c0Gv E9z|ԲhN唥.|A7ٲ4!do뒸<^z65ԑ'~;;h5{Aa(h(WTdOX`.īr[̱W7ކ ZSZ?T 5e'Aa-JÂ#P$~ Z²FB9@[$~$!ǟ48PS1msվ]<.6z+EeJӑ.OL腇yIUN)A* %hӟia&G%HPP&Ńqr D{qbPW%]L =<Xuf~]\c}s5e "wOvŪV3qEtd&1W)X';[ Z LϤPLh2vV,.TTzWan⬅TrkO 1؟ݔ#50mrXyOAW64Hx87.W]'<% n fݧ!J}fǴ5nc[e,dxZK.C2~@cxSQ{i<5FT*&xif٭ϝ;, NA12T)wBBHS~ @1А) ,jpux P3F.5瀥6N֛5[1M#nTVs yL6LN)"NzY.5 ?VmSP>!Dæ$j0,ŹkY-ln!0qs7zgRL99岩!R'aR bjAA;`/~a!?Zk`;_FلRWe]vҍ&+?_k*\~?|U)WD[ˤ})VY I/N#A-x5HtZ EV|ܓo=HZB[ tSTK`e)ݲH!?bܓv jAG욳>ChgD#ձu+ , naCԄ[unȭ4$ _O 2nRLoE Z(SaZ(̥Hb;K֍;x~Udc܅jҨvv/?5(=3w޳1mق *]{0)+85гU 3|9L9dZaXw+Ks%@ZCB 7U/#) L{aP_%BdPi/9msFű4_;ER+*koԖY1ۅU 7^2b}O ԲMvԉ?bW0VcRꕉKJ`9OpYȝy%?h#ZݪRRFkAlE>{P| Hj-|ӆ1s*oB]\m!8H<2W ADO,Ldfm9{ '!3_Ľw{]`fI$~Gk fPUW;0G=yq:iu? Y2]7{]*ELBԓV@,^8 [&D ʑI)[tIEfJZH膟fP3͆D) b't' G(>/J$!JI>6.OnGhXi`"VD~v@~3m $W(I0Y4c)^FjF6EXI]>^96џ {ĴaݭZB>ۻѻΦ1x'mOvр4CE<:Rcʪg%m[4=igO*P:oNF;R..aʕzEO>Uz;#1=`:ʘ. Fk LZ(" Z2LLȱixYv998Yȗ4 }l،&1\܈1aU5 n`4k*Sg]j}וrF1w+G>;3O*MԻ^7&F7GipEY6uZx/{=7O8$zƉ!bj5~e bW9@/{ߦDAky9EҦ: 4‡E ''xF#Τ0{)EaެuBK!xJ٢@p6 !Zouaø N7˛$VvQt9ҡH=?/78' ꎒYρV?]O+/կmH8E/<-uV>Luq6CbV4a3a!)Bz ԬT5دQ^ţh fyf7 ФO ܯliCP6,՞ L/~»|vlZ%o[75boOE3Y2|8MM ^eDR|\+@mZ’û:L3$HTmX3R3t'*H.kT}$ɠX`_If 1ϵ)`B"ئ$ňz&4n83 ˠWk'Gvя/ѭ:?b?\}Tf\cu.a]1Movlook8Lhmvߜw6j 2 !@ςNVF%C/`vL@}?T oc(Ha*$NPifSJK'xkWQCG7Pn#TYZpe^qtpD2 %ˮP( ,\R΍s U?lFr<".tV :CU@1kt>#4i2S"U17ĢpAy)̙Q)_jp{M߿t#.[T>&֦3]o&x}X'i!0Cs,{[3/;C#9||S0Cf֧M/<xEl~s ~-#$ [<]f W3||ď\Wybjힲ L )P"A8Ze0 8 =Ǣ}l"S,ǍNB)"gWSo'&}4 v 's)Dck~# ؉k^+s2ײV$*ז=8CNW>HL,11k{)&+IcF1Қ_ 1p렭*]t8L3'oN!ؾN  ֛I9md eixJ4>r0 .}M`dxZ:F7((^^ؾWg;i(\8۰C͑oKPѐCJ' (u@ ,bZ)zIy.RppeWp-p 0ߨci-(?yk7Gyޠ9O=]ujqb ڶg]1Br <="BGm'nR d(gʋZH4zpcg?$!B.t!Ӡ.ij̉8Q `51 hkhޓ#{tz{o%Q!?v=ǀ]*9i~Bxrj<Ϊ3kj-z{2NPE+FݫӪU!".W6xN؉X4gJsR5gηaZ}sVh]eĀƣRHg1w>4 BXĐsZWI2,=hUx"a%zQ=kՒ)°TSW_fo)d%?B~64kwFHԉV D.F]t W> ]@~htV4n-xb& t+nZ .vNm\r}n {BD T a{|X)Ϳk]}y&|ZI{ڶ0i]QabS\;qv)B>'#@49ۦ@>MA9lWy[v^=ﵝ0Dk^]"#lH ShMt h SuuH\T_K$r Pcl:EGے'*!aI})̽zϨTxk̩lxмD0N{3_\%݄j96&e:"ڀִ҅F b[oJD.WT@ЮFF+,mXu2-,rk$nn*L.2p 0G|K ("67D֯o OP}2iMP1I:Ƙ'A$R~sZZ9@<wQ#EOO۬Y1cpaitQb#Tr)f,$ {oȭz'"uTQG-!2́0t}W7'LS˗߄y+/<- ٮCR%hckeI&p~E)ԕNa,sj"è1GB\Cc. 'T6]:|.1\Μ mX!?&sumAζ#jS`T¹!>1Y/^~,0@3b`CL>;#( p  cج}C=j.S[A,6'+~?ΓYt;3r|Pτ|A-aLEq0Z)0:sp0*6ə fS6ɐcT: ':jv=IEob_܊OlǴ_ac΁{TCzzԛ xН{?g00x;V)q#9lCxп*X)7yrw0ޖ֍,O/‡l05޻bʂh ^ڼh ȵ 591)X@zBiNIP ۟h;dÂ9,d0"Z-LsiOUyFֿi6 *(SU>I_AIFi;OA >v,A2L y ~չƮW2Q`Eps@Ѻtl{zVq]whkRRq,1 G kONӛ[E";w݋ s I^l_ނ3-R'>tM䶁+]7DI0yd" 0\NR)Eߍߠ¾9/]|C}qAtOS`<JYcNϛcIkA%,P?$MZ/TJ ŊhVn+TaGfB^@Z۹opUyk`R {\b09?:?RjL8sn8=p3ߍC2.I~@E8[JqK̓9.aY98g1d CaYTBk<Susn" 0/lNuub-n;ߎ㫶eo> Wy9ã3u~ Xf-TICh׺7A)C~ތ#Yѕǝm :\qA߫=4KxcdV5n?Ѫ s%FcL"p:cs6Pb&6fc~;t;DHYOCফD?$Ǩ`R|?dy9*-w W:qrz B$/}u2l]c=}qa GPt9Ѷ',28Yiϛ]Se}\$:䌔~r-Dt3RhLm,FC ll|q0iKIv^jE>X+ ths$07&r3#֤ MӔ\,Z#[R?&/dQ.3F8hvx/2Pљg/1C+ɂVnU/Y.3X !lbH)BMTVíTW#VvQJ;ҤmAd, mݚi{J 'nFRK.Cb`!ˍnUK-䙀7YJ6G?%K~~!˺{c;1.(~Yى8|~Ycws3'^Z#)wk ;Ba]F:G#eTOmU9 Z#D ضS;+s"NZ:U&kcm|'?T#r+AY mZYO{ yLUV:]znմs'> Yָ UBGwTn7K>F1ŢPCz'*m|xS1c9.?GN03<xFpvm' fomo}<غdj#Wm ;CaoȄKLulisWj5L~QH{a 8ĆR # ֌Cql]yc"N%&+,'?96>&4R}a.j6@l8iKLW< #R&`AėRlVBN%A+u`FdlVUHN"wzg*mĒ3&TJ$TyO2j:i& OVAwzM5 `_J:cNմB_U_R[Re~E03hZww3.LJ^D(ztabNU͠tY5=Mŏk;vK(x~܍şQb*BŽ$L$8!ge_Eu`R%K<5dF[*Z^|ƌ&f" V ;x,L"2Q߆&2 2wP ZrPrs䄅!hrw\t>aS|UXHv-. T\[D%^$BTMj6@יwk)Bsӏ!F{oipZIx뉠[ |% nάGDd *qX_R|.qnl,PD gUx~¼I@-2WcNwjWHcJ!U\i 4{F]\Vt q}!E\9hфԾ={*1 h5r"0QݸDL2<- :s.E}gq# PL,¯U3 B{Y:Ck1ӜXO(嶗k)МmKOSfrҎNj&>fRI&in>d8Kd"]6~| ]9UKM4L.x> }{!{_\%N8ml=}6=2<v/a2xsAd A1>F5r_f"w^$oUo{H>>W8 5xn>9z3rHI,2|=hS魨0d>rXpOW3cwpwvA;*nW/ .PQuD+@*?:}E: ~$8ݬէ9f{)5δRA^ [vhKe%s -fL"-iF gq>Ӏ'AX` utsU7(G߼>|> ̈gQE!3rN;Zz-2y Q)=NCI/_Vod[UݧtWL)nLŸF+9lM nha y¶Qм{*?mEZ&Jۂ?'?Bϓ r/O_ȸj]! #/͇VsP L{1Af*Z>$ufV_kAOEإ *H>c{/^h7@gm*f[#r WfAْ{}(j0J?e hO:1ʑDPtE^Tr eh9 o>ӃPLqw:qR:OFtD 3PGW9b4>).(yIZu"U" #Ձֻ"Ƒ}dx 3W i]yOAwT"`g xg \P螻ljXE_ 1uX.FR!vTڱm쿳2Fw& pFE7{ў$*} <oCi_fIZ&5qQt]}t%&=C SLa@@kJEH(ɢDKJoҖɹ+ ) oՅ}|Zt?}@c/xO_8wE.5~Hue(}u7 (h2wl2{ͮ"h<ײ fT❄&X*\/.GO$[=;Cs>⑖fB 0xP2e]FS6/[|ދ;n?sQ Jf/@ B`- YҊASTTO9r!i” ׼bhZU^Eb T*, c&IqmElL /AQʎ~1 A6 9.a)c\0ڙnN E4|jAd~%3/ܙQ^:'P$n=aZ~{9YK lPt/)լNtYnDv#Jbl%N6K/̏ՀH?h&c=&jDs鿺l W /iNP~_ڹBcu]OM{g3}[lQP0 !LEQ9kL-o.ĘT.O,F_1Xj>"  5\e3r,=iE!5S?Lz{8<5=[NÝ̞k'(3 ^gIqġ4h͘H86mf rm 4$_qWkژ/1 }-Bep ޣ ʩIuY4j_Z t% "n'j!4 |~J,"z CKX#O~jj `w-'9'zljO2N>|q]7]r0lR4Y8tU&Ol(nEL+28ߝˠ@yNXS">:Utf8 VG}-R,xOIZ k9-]֊Ēl6h|p9-ǴHZn>"j, 6OmױmY2*~ pHI (tC٪ٔv]4Q7?;R_7uYd50w6$Ľl8a6j(eWs):`B`(7xB;?y]:o%HT \Ds',|'Sx7;L OTjf_FʾYM tNMc^{J1Sv"d#xOj7"ǪBsAfM>RDJk] Z\f uF 7y閸: >apx V Zݽ%(6ؚإ9-tބz?X}+]Jq|~iG| "57B4&rE71)6&ewNC?VvrXzGFo@Yf{BAyYe&ߩ/8 qV2Wke|,'$E}&8| 6{BOSts 8-RC8+mJȝ`ZxJ-wBl9c!䛳B}r~9Z-JZ*N)LT奲kMc2HN]0ެ.hT4Oѷx@B,h|. p*w#{x|6Ӆ'yc wo@}6"oܗB6G-Ȧ-CQOHjm CKmk^[ !!(gA #)1)z۩dS+-Pm*tj%4^#œbЂ-v5 9̓]憽&D߭Ӵn;e@T%Y)찶0Ӂw(;Y0k6vZkLC77'#zM'DZGn=TL5C`-YL]`ƩXKeJ!]=?v"{ ni Tu Xk]q/!%s )^U>!j+thc}aӜ5Bl|hvedLL{(9盻]SeǵtWO`繠=''պ"'dl₞r@Z7IѨb|[uF@֭}c^ V??7v|Ԕ:֦.٢=ʧRa7r)E= рB]4.p0nEJV3)F ZlNMQn=UX%-+n&qPUNU>'^&e@P,cΔɕ(*XuGR;;V:#žf٠3"HI?iɿdGT> W]|w M+ٍ \LDd*y F_ﯟO>x?FɁT}3 "$ 4@;G`G=- WڈM [$5:j|riueg <ȈZ e'&$ǘpUpJm*:+ ZP.Ìa`/ޤ+@d-onx]DCG nC,:𿐭 4Wp]<ꇫnO~0Tԑ ziۏ5ŮC`u q^r+7фkED ²TvZS@I^:N !)}NI˛eswbp5VIp[.NEs =ŧNC#G"bR*؄K;<<>AezO0Yͺ]F8l6H'9Ar_ x{b4w"R|8zZͽZBsix_]Sw^fOtx]k=rzVى?ĴqLkgPE]*Q jXXL*ҫ7،ԏB^􀣿#_xvT3.:lT M ڦSzF#$ad9YW+b#`F~Ik&HAMŧwmR9S="k= -ڟi4ƜQCUTmxL1_`a7Os.SJxʉnm{8V$|Yrot,rv"\Z@99-g-ods߇θB+'"VYo.?y;sNPvov(y슶v,ďT ?Za+*i}YxϨo'IGKR%cl Repn~ʶG#"-3X_+%g00a#f.BpR0̔0F"\Bˊ$c?JWY?1уdP*ZeU\%j̒" ZNi&Fl퍌5G{j?+JlRPGr(awfWj;m9"fLC"x:dގ03`jH5&)9M^74d4XM  Մ}@armYMa=N&#?o |K@{_e+t )Ҷl2zG{\ש6 pǎ`e a'&a$L#bBFW<7 ;צ#EW xjtA ׅ؜DiYGR~>,@l^Wo+Z_+(:7΃p't:oV:b `n|Uy8-sH S[Î>1|D5|zY{eSCy=Hh ;GTP0 |4#?"ϓ xb[ JR"8?D*Ok>= c+f* %: syը-ceW~$,]H9GՏBW ̸xOZɶwxeXa"N: ݩa:ktbț hbwc''3R]vy'/RS%-An+H%\!)+ 'd@*\:HYě%*( c̫uUwE`q6kGdd2`pB-NMXd˖ ؍[ʪcG })nN /u-ioS#sn<43oS^qf*"v !cLr# *-Le{?Ut~!E5wS^|:Jj/-MKM;S¾IfG Qefѱۛ :l d9"4MnKuqu~ E0k*T m 6CE6 aӶ7+- O͛f~%,^X-o?(5E] v5| eC ?TPVوzQ_(92Yz-(0TOVRw@fkWHxb}2[wS~fyⱼ{xQ*KeGP&|z۶+Ip{fzțh_怌7hMܨݎyWș-Rt8(h 1A .d?E9d1-SDgtOtn1sy\IN\ې~U-5)ج/XJ _fYZ鞍[ Rc3Z4oyp^$0|CIFN{x Qg{jפ~>,;֬' oLDU'd1h](Bm@nuxe{Ӹ W1$Eآh (Q翚ƗOE/ŧ_+g[PoBieJ }C^4Z]z7߾F}irlFk۬+` jE.{X0Ԉ!\n#:~ U,#e1l|{;:]啨6@w} IvYLaJzL$J%uo.ʆ T% DǚrX#;np(!KS1zRdIVu$SυuRܾ2ՖS츕fɍص LkLV9mܮӗlT4Et_Yc1,Xl)&zE>Z8eh޿c);{ 5\ǧ-X[Pi 0"+7O{] 7J p\,{20#5gQ;(| Vll(+]u,JGi$DZٔL+P@ֳ2x)D/hNPURouW^ݓgmkG ߮fE|x'yB1KoZ&;x3bge7S&hףZ{Fo1pmlꏭ\hvkwQe..xX$c<*ŲęJ+^b v3T5ی}@fA!M+zuU9"MvyU/߈2?^{':ဨQ6)u_1/)2:2ݕXTA@ =*ko\mTcfs+TU~@|O5 =GMq Y=S2{~X3!|V}6_h,R\1W5U`;( M R;?4wP4:7U+$1N@jQʹ̥!,ɄnZtTљs=9G8>WKNRf 2]oFo>6fr_կ嗎?~W10Ev_]g N…mhE8wϰzIAܩQk,r_ff vÕ) tZ R :i@)c2>ixy\N#wx8,Dx N`󃬐 M9}hxL>jAVe}~KPS2_ɷ|> A~ΐ>hKU 붥}Q#]?G*CWt" !((&7]QsU%X_${c}<:>@ӻnn]@̈́ 6xJEhL+Pi3 rAаb*(plE=Jb,6eA!C*¼F0i̴CU/hKn6q&1+"k2At`ۙnȗ{D{/(Di05Ht X9Tj-$z A!΁[RkdFsU6螈S1Tҳd/Ua~h`ߩ2Ḭ./_Wk>s=H{ HoYʾ$/*) X0(3C#!QjڝHQTFTC1غ:fJG$TO$?ύMTP(&yV腾oTnnۄ~+8G22v#a0lHh:*<b*{Suh _IH<2X -D y,kv粷?5i]z.gī)/!]`c -'+^~9Ԁ=fJ_Ҙ]:5?ƀe{A|_d]vDUl U#pn؏/Y1RXa;<`CG 8lwrԳh@zZhB\*@xpoX;DߣX 0 S =N Qr ,b[ꫩ%.<ⱳoy\BB>I}#46&3ے[kG?6W{SSw'VV֣o3[ƎwZjjCu.= * }t8ں,C,Biw|`}r/maҫ2vjYq# bs3j<־'|+Xy@%^&}#!|حQ8h BȻHgn(i/^[ԦAd}W28`,7\<4\y/,aKbb]o@W5\1y0z$:Vz4zǕv8!joUpZs񥦳k"6@u;ɧhxC;*~q~e &zf'N7M7$b\|1t1O3sr9xiRXM>;. ܀@mY2 )KY׸mR%Pdn@)(3[LΆ2rZLy;e ؍Sã8~RM#h6q_([`]yJ&\Ǜm漂?kdEd?[{87M4(:[G\}Y%)?u " rb)bRƒ^K%q͆䶞ȁmB|ąXsu AkiJ oO.1I:0v\0OG5;GFBcm.ٴ[| 4=/3Шݤ2f [X!"zI;56dj: $-'~0$FF fZUStcۆ_UA'W80=xbG̯UtA`u}t2D?Õ'zoP ѢJ`$!*A^lF賈/MH=۶=wG kr7<_ZB>PH*RuD/\xPJUӯ [%8(d(ފ:geD{Ak"iC=E+l96"P`wzǧ'n75X #Nb; ƭ 0^ᰌ9%dY@jS_n 89`<(;(7nPe! }GktIBH 3R6lK0 Lk|rOncb6 @:/˰ͭXլx @0 AQ(qs+bN@*Il[< *Ap^B͵~"Be}v:fk5<<0qLSuqXd6ľrJ`u n Uu-E'-lҍgQA}\o"CxyO]jY4#edRT2d'Mk4A_e"ܘ>hO%>rl^)<BfFw(o;|e22hv$p4WFo2u q6RCXo#dAV(-άMqU%\2HV'3!vL)E "sFLi9wcp3 "kم{ &۫(<yl=:<<ӱĽf~CYj&{,~sui-*Sa-CcJkّhlYN:#=JN/n&#Ȧ‚8y1^pF 7B\)ABJZN0j?/iq%H!Ƴps<]]:bBmbO^U>'ĝ'9jS3+`*Aq-ӵ7D =m %G^)GOXsA X?odS"Ѐ_8YE>(NK(m'*C cͷkf\*&&+'H'QS]d퐋ī \DDz:ܵzah/ h /D_Tl۫Qҿ[IrtyS&?N|ԒT Ry#J0"l;c~Pz~n .Q׾i2HɪsSTgpGHTu]v%BչG0ʊM[ű!;{kveu)8\BDbVӌG;%(Ql,@NJO-0sXCʹm kq:+ٗzfFy ~ru>`ݯ~x!AD}!suВI^\ dIDOmc_U€YpRq aX=ZH=n N Tx@@ZV7ۈ,LϽWGi.[`@WTJ4ʢ zE⿊k;(V &K=OB.ܜ9`?w4@N;ɜq ğB=8!2 ;ak5`~PZFZ̦vmˊh,{{u~$.\DNx=b 6wb{9igDphB~ ޅXKQ>B҇IP@YW>, 2vc\Mįmz!KuL/}C$Z2~51-o8+`/Ꝅx.F ټo&$sM)vՍD`a&mjfסQJ?wZ4A2'ItQ54gbrEԏ'FoYӉ@yc?J E6w88>h'l8kt.Rca~Z 7KoBqcVЉ U'0b噛 eJQ\YhUށC_sbJzO*gIWR\r"=PU ?|cYN-^Ń1fbaUV! P>*VQw5f`гD;YFvD"# /ߧ(s75Dp7Ǎ<5.o5mz\k*ǴM'k(CybWYv|,V޾mwnz yN42##k }.;䦿FS8$@P/Soe ҹBf~ƱWP3_(?a xp0 t4sK[A.p\RF.Ф꣐,:we)$h7{W)ؒq7J,2t\sQÄM1wm}/P d]ʐtI P,8/PSy~(陀\{grF'?{K<*dkTPKخsR TV**%˞-8]> Y鏑Iߑ927L|5ƒus;N:}t8t ˳[9~eoNI ?~foÌTlW*wDnqf+Y쏹IÆ?yɜ& e8b8!a$T?/`X#t-/@`|6h,{_"T g Ϛ$hmv"L}oي;jh_|y^ m~>`# c Cm\`$EIQqArsp՚"v6Tp}Sp&{jg/@9ƓK,LMH 5O8lQ^ -FH'ҍ<]2}z*IםK(WGa0V^%itr,U\,V  6A?C yw m'DWC5<%ÜXr\A] QtG)"zQؾ«[cM?La0x5*[_=r\ ( I\3>e 3 xg6 G2,$pξK{ZOww }SGC[<o 3ڊ&JEHx1`C%,..~lA s{Ϙ};-t?27|o:58ưnpHjI8Zts_ŋjů >ddocCOn>ѩu ׋FN~z)HQ\>(!4 +^׾A.ǡ>vo'ڰ;Oy]ܣ3Sq @֗#w/^I.R:Q^xB#xJ'3{+uWWѴ UK_b7UƔaoYhIj$E#QxJ\* Ͼ*|1|h;߄ߌxr pVW6o|бһ5?$i9+*Bh(C@)9 O/Ex8*pkikmf81/(T'_]wqBA' Wg-21?4vK`^ akAWUݐVZ[:w6dHW&ڊ 8Tη<=O)N7tJ.PkQ2=g-Ie%)N0\`:=Q5fK#6ڶz)[Ĥl0=gSa;DRب(AWfOqp-] k$vr.n (9+H$Ǥ%~ۭʥe(d aP@ )`9 ^hg?iofYu v띅x)/ႼQFrCG'3ҘZtu`I=a @U}mLd}<xf`{!T1;ovɺJ;{죽0ۡ;^>W}OqhWGj:J*>՞ָC8IW\B`8TImƄ5QAGak2dqWӝ pVP* qSg <}cK"p2yqy0FPxe[YMQ)I쁡,[O$IAv;W~;n$F|CM>^aoUa wXlfna}ƹfE> #;̚<'I껕7śTVvgzJZs=Kz~$2yt7<9a {!ԅU4BND~u K嵜!MIk}b7ԛ2{2垯%UAɊhgn#"Rl9OhUid0J=] ğRW"}w͗  "^8tǢQNj]XK<2/0[.t.\RZa ǔTV{(i1rm7Gl,L2sAueoXEVEnM4i`nZ;%$spia^ԉ2:wF'u m5RZ|CޚIqDh[/sdqЌ6Q,T.ЮN](ihny9nO`wfĒ3;~! fSZ]do}d68+T%moo>M7icQH|3)B=&A?hFgKLYuF%U7~ RE.miY- PR=D0e`pqw|F%Mf@>&V!aG }/zhiIh1jav aI<$cg/¡Sq%e%i6 $0Q:Tzx̗ȻVNP` 2֌8E߯P@<`*ͷg@~oJvkN@):7Pޚm#1f۔[Z-%Ekb[fZ6݊3rci>_(P;-$5`46k(SxܘuJ}}*}=U9EgF3!9e*"ЯT%{6AԳ,w\eu7#.{y2ngwI٭Sk/~9`*v1B'?7B}W|@s61nIl'-T;H+IȨPm`kGkpɱwђ63Lcn=ȱFJwQvcLO5 iDJ鑧.K{1y g?o`7Is=U,xo`TXˤ_jEH8ylJ@y|q6z#@:{cWޯ{-6ɨ}8DE[^?5uW3c9]=co녪I *.W(}*7hs*` GgH D(7' yDꩮeRFF9T' z"h(ƠEk!M % ՗xjM֮c=֌K>L6H'J/`35P",3zdYi՚P~O(zz;Wz</G$Fh'xj!^$:L|[qbc8pVj2td)u7,cosY\;"5,[\7cĕo^r9)ЙJ~hCf#h\ *q[^#eL4 ABs>H5p2ʋ_Szdet$YmIO"?CJnIO&wt4!al-QY2}d;6Mq`8O  IGAdv _]Ϥz$\,h73d} rSz3'ݲ>G_ BgA[8@W%-$W JL3tq͊Mͷų|v*vu?Z`" 0,CcjT̲ QSeh߮}jwKWϳޠ֩кui݈*Њ]6l~%K!2B [Xn{4TIxZ;eW GFq=(T{0623\`T4l.X!]b$UYQ!";l%(z-[Վl3З KrNGAxcAYkmk!tw ř9\@St2)ЩQ"o99O^_RKbSېMcfeiʈ*KݡTطlhHŽ"XNpGo_mDoℭ5oq)JjYP{)R-}y9>/ YtTLy4MSx6yU0!~Ƙ|Oe0^7X:h% q'҃HgxN {K>+qkq a=cadabra-1.39/osx/cadabra.bundle000066400000000000000000000012311234107666300164110ustar00rootroot00000000000000 /usr/local/opt/gtk+-quartz Info.plist /usr/local/bin/xcadabra ${prefix}/lib/gtk-2.0 cadabra-1.39/osx/dylibbundler/000077500000000000000000000000001234107666300163235ustar00rootroot00000000000000cadabra-1.39/osx/dylibbundler/README000066400000000000000000000001261234107666300172020ustar00rootroot00000000000000My private modifications to the dylibbundler program to generate Mac OS X app bundles.cadabra-1.39/osx/dylibbundler/dylibbundler.png000066400000000000000000000502061234107666300215130ustar00rootroot00000000000000PNG  IHDR:*vTq pHYs  tIME  IDATxidu&v{fef{wIvTdE$40^!',`>F1di`Ɛ9l.M^kʭr=np"޸dv-YU=nsc dYf!, eY2Yfep,2fY2,kfe52fYf\3, e52Yfep, eY2,kfep,2fYf\3o<;=6TB!O&pif2>I$I"PJBr\P'w'c191TZ Ð1fy5g}q/!R*8eVJqDZR#1FK)ǥl6]%JiJ8 q(CG̞F)RI!ZM B |'qi7|>宙e7VnR9_|J!QVyBL'1s] b@BƸ8RJ?9'$I}S)D">{!|"yBbLl%eGPJcII|. 1Z+ чJ)JI1ژvXk.  ;۸hϡ;0,( *Ù=|8|Ʃ Q%R6:mVT7-wqzn)Oh3fs97?XպNcڱm8d@穌1=w[U2CnsR ${R%}!>uBr_O;(OUxB1i'cRĴQB*n? n< Z8\>MoJM}0 r?2)eLDk PZk%T)LJ^/;TMR[6}i-->ؘ$;W*'ޔjn?DDZ$Qqg.[pkRJ+e[,[CO}'Bq)<"l;lSl;$9>)*\~AQj50tۇOtJῲ}I+сN{O}Qq;fidZ$ &qRSf}<} q0 QVZugoIl"j#JO-Tz#|ӎ|lap_fkIDu(O׫WoA^?/>!4ciT1!iLe;U i}v'X͖y,=wC3ۮl;-S*vyZɉ@_2 ??>c;b(gfos{{{rrR*h6KManJɤnl.tg5i`Pd0- q\o^3rLC{5zoڪ__~_kjևkHJ)6Tp?~#6)Bףv1}7/$-d^!34tqK&Ib5!$V?\z-yP`vX677Uz-/a GOt f{"uqB(e(ՁظWӢ'Bؕ@4v̶AQ0Hހ㸮h4i*5at411`v611Q.먚/E@޹sgcck_Z4e;' q$jRf_} vL:ζ i0)Ц]2ԄvX9jhW֤ [GlXJ}OM09wqHV}(wꫯo:"(:(#ѽ.Le )@9^gA{Xa]WUĞPJ=kZ}j{ݰUy(jڵgΝNx}*t,]lJ _*; 0Z:^+naҁw B@tmѢ>6E:$1N[ = 'V)=}p 9s8a*a40@t =ζ6~nqyhf;@Oә%'w+ORJ+Ç SE8J@ȀT{zc1fh۟g\E:=-VBuR@a6]Bw+ qi~jmwER3*mm/KfvFk-|GQ S!ymֿr"&/3oZzpS+w$b1HӲ y3gΌ8RkZku>u5}N}.(yWd2| 5y<[\\pE)VL=5]&]L 3Բ1ieEqS꺞U*O<~dAGw;\JbJsȅ0"Sa Rmxcn=V*Tg~d8NZVgϞ)31)y2ԕ^R9"5Sro@o.!R8KK)m<0JMv I_ =X#Ax@i?7 /_>sL.5tڀֆa ]SAЊAeT7zCߙq}ھVĘ9Q w1c.q9YuB_f_7y!Wܥ$`.?`:B%y.C܏w oݺuȑI+Гc "n0Đk훦*RCQ}0°Kun lFzB<]{`ܵ){hKoD ?Z dkH unY7~BT0j  @yv^?vu[.YH Q1娡@ҙmLK#xXAuO* #WHZ:- ”f|R05NVdKM͔HCȖv X$ _zٳa]w!y&L#W)jt9/0lS!#fƀF5և/D{WHh{Z=$b{wӋϡC [>DtNqk׮AX9p4c#) K)`}5(qZVױ+[<B5((m a)Q ?#R-zS~-SbznGHm2&8rI%,{=wha:CUP 'GԷ>;I )vb{Po?HߟBg](۷gff:.2u7Hy"lupR'QNtkuhqp9jXf;P" c|h$q6\.ÏŻίq zBT=.^#Vt.}'hĖIǏ LW) }Hc <8HD=&Heh7Ю!dڱ yj7=w91Ty*Ga} 5챃yƷ=y4@|O'/\[[[XXPJa S'cB֦# M[jCREvB eNԤR&IlE=~RS2U[>0I.ʆvt3eݺuɓ1ݎKꋕ󷟽[BevAT;"EAlAژN 16B$ƄEQOt}W̩[|TM*fC}ScWi£ |ܼyQZXkm\^򁦓B!Ԧ?=^!nTlQ ƆKzF$R ua (}|pŊ=ma>QҔ tl*122266h إqV]tHl0 6 ]!NH\ MW6GC UB'Bj}jFW'Z+bSAާ4GA}V977]c5(e` 1P$)hś$ lޚqgz"5iR~}v^In2I f' G=5pM_c>um1Olsgα0/tt*kjےZ[Rpva&!w #H e"Hmp N@cL @ʏ9δ kަi^W7_|1啕B7qhWcbx"Cێ8$mW[k RA/rTvd]L-k7AB@8H6pi)dM7`c9YZ:~X)vy/RJ5hJ(t˳ҀS~o)AuI=()13mCbhUwwJ05Əf_ n$WkrN?Y0L 67LLO c (3> Хuz5 eam0ݻ1io3`!˧gLs6w< I~@ Jh KfJ;d 7uf\XY3 =m?hptE!޶N_q]ı(~os8:I~JM)+5=ji@ ӯxfۑX԰htZ t<۪iW4F{\yᅗ 役c~wMMRƈVl9 MùRFZ|}BB6\AFe+y杖br{ByOϵ;7i N2ӵAo{i126ʀ1R^{`R0zKAIRI?/;?"@A{!4 '庮&TJDZiǺ.\NWtTjc Kh8`Kt ^ :.jJXQJUR?_nMO{ cZ_n'+;oXopiFièsOܸQ9chBr7aq1igC+5e%A+{{QwNV-~I׶h }ݪ@( Jk)凗^Frx\cs+W6y_{=t{W~3/gx3SQU.;j涚sD$J |E'ߙ>GKM}O(1fssѨc:8u 3ƨMnk3U-5u|%6S3iZۋwMLmnRΟ.roť{fF=󜞟𥋮rLM9Gʝ]p}LMjH8掋OE?yzhai|!V").z2!sێPJRۈiЎvG/FS(ftU-Z8 IDAT.Z}u|$`%NJaňBf{ M@&ֵۍ(gTk$qh8SGFFhኬ̻\ z}cc/v繾{vq8tV7mDjND,;q8thSu!ZZNld @ZIuSҧl~To|GWFgggs|G~TRnWb`&~?/L_$׫QRJr;70AzGUT:RS|~.6Yrk pT,"߄0 +88\Ѕt=epkkkZkXM):q Qg[+\]QYھ+(.L|Ri Y[K?YgN\8q4gLJ;/9 8K{. ]PJ”j9=sta> }z8c^wΟOipJ]^MyR$Ic<\Ngi5epيcd0~(j޽{(l8mܾql 9hc͖){G3~n8\1.Ononލջ`o쪛c}Zq`)j_'YjJGsxptRΝ;ۓnAXE3Up U,ε_A)uy!+/q9|a,z^\Z+:ai2>Fqĥ PqerEnjVTwU׶t_zJwsF)#Pc5Rw;vsOŠQY7._tA+Ic\.gL7JM>5"Mټz*cu]ƘVڱFwF{Ȝ ع{kH.s3G?'7#뱾Ƃ/us908a}QSkZB.mVn.Ŋ\:A{^RR|td!Pcurk1iEh(tH5݃sa=͹D2KKM?PJ)q{2`쀵qx}1 -Қ1fccRK)M# Hז0稊N)m+3Mv}lji*2Rr㰤Qo*aỈɱ/F81ؑAT]E"Nd͕fSQތНu"ڸrϮ?vc&8gN{;hJ5w<JQ0VB<5~{M}}>fBu)%{8wBAm5= ύR`4hmV~v|Jnc'B@" N/jovbsrٌDH)ʽa=sL'OךQrѹz.TBV;ﰚvg;zd$wl1; [C ŒQwVRUEHo `gg 2ä/ YeAUx H)Y^~ȑ#[8_>@"V-P1YtP+oH[h!ڝVp)ʙaPN\EdleRG,ˁ3 [ |9c$R$buvn3;Jr LNOHy]ƽscrys"f&*ǎWn(J %Tj)WD:D81|1?l+G ıZ8*Ւi@~d6}'NZnAK) 0]f"p'ʠ֩4%juœP EcDH%2N[.qBh4kG @Qخ+F8Bȕ坖-z3' M<\;6]4άؔ77h>zkT٫6-^ѻ5m+V@(%V7LJQބjx>3[jϧ =uiWy*{<̻>ME+a@ud0lݻ!jn4]^UZV`'SMǩB{!@A`\) L|DB+faXv+bzj%*jirsy;Dca8x!pC-漂0r"J&Zs(edܒjҙVVҡ$I1ِYniPb 4ڮ"k/=2&Օ{&#S/}K/d,$QY[;rRtOwDϖv I)766R6ê#\(B7F.@[ՠSE;dr\F3Bb8BxHƯ׎CDn)YYl4Z-!T+wr?I1)\XN (Pt]F' 1kʈDJ 'B^Cd H񩍥5CaZvZ͕?ӿNLp秦9} ֬>:~X9ӻ>"\֤3|yW F!di5b9NqƪUn;B; K ;!ef 'nkprlFB^Sqw|4uy~ (( 0*)'J#5P(-5ƧI(:W7ה֔jH꥽gA!d(ݠɉKa9wո՟J¹:7w؃"XM:C`!j.@=:S:~_TT*KϗcC)e.kZСuj;Kx p24J ˝' ;gFNhD )Kk;kB+KŅW(_83=1S=R \誀RЌ:hMQR!b\iM88hy>2!ThyKZ|;qn- x;7;*aN>29~F΃pԫ^ؽK38}#"3ʦ8ODȃV֙R,õ[[[qUj_[5( BѰTnoW: n3@\ J0P-oN?qH(pvv[(n %BlVWw8g?]=yDZzp'ϟ=Sf sh)2 V$ pe >I"U>2٥&yAHXf3@|b&FG6͉]'7-l>\(ʼbx(5»UJή0!6N3-:rRI!AQX ;.Ph\Z 㛭b#D K;;rܗq.HDGqԪ.nipb٣s8Hc#}_Ii4J(0WϥT.519[x$NG&|)t. {24YډdkRVF(lܾzg/>㠬t%4$rk´_LTVֵZpVel\AEH @U=XG^Rz" g] k]lFI,t"en7N=~~y.RfQZcZ+)J*!J )RFqyXzs?q/jř_83]/)7U I˦0ry!N,3cn_|qp<'(0B)jRI,cI#}F@_-} '=~̻>k8Πh}>~Jt!:aԔB ^ւH ;Bg:ؽ U3T۾֢bU$ -[f"b!DY//&_?u|.~;9%igJZ Ji)R)sGR{?Dgf JQTՒ߿'Oח[&jġJ(g!5TZ̃&~~Iȼc5}W8x ~l6Ţ+Ӯ5]N[WyR*" Tg/ᬕZI)o]hm'PB8D;{o~+a W3MiVƀ'ZIBJJHuXR6ZQKү݉Ր&>LS;o|ʝɺɁi€P%n5CP`r{%R`GA:y?F_cǒ$ m LiN}5CӑP*jzq6_s]6#%*IT";%_?s\ C:iŦj)F3 Jh.i O]J)-R*R\.'=qx"DVo4wvƥ3_|~߽}֥/ h0F0 ZD)idB @V(Rfc+2•R6*8kH)n6idϯZ&ފh@NRۗ/ҮX8Z!b뻉vc~Ws\y9;ehJB30B5B)mVOŘYIr{sGUJkrŕzBnƍzR633 b.MD4MJ50f(g|tWUfU|wVc* I\x1$Il#>JZ}XM8lDl6"M(êm+zq{ynRĔM@ljX\mƾy3A~.YXSw10_b 5[m 0Ì1L¥JQhKbq]zfsvfRBx|bh ?U{_}Gh.S%d@s[/}i!&u>»$yժjccc¶O cccj.c1^ђrdO{[ׅ1btêݎ"׮)jQozhC6k[rљK^yTlw[v{sgI,uB hMP;w猱aI$Il68X\\\__S"豓k Fb?|Džόx~SGNOH@ɊpZe(Q΢VF?\YYӠ̣!o} m8iaΙF~VaؒxX {!DǾJ N+kTjmݽn^i4w7˨'?O}̅C sWXbk:<0.sqhgNV7o\\\,ZkL1R NkF?so%%8ryc"A6g'ҥqO9n&k"' .,..nmm/ ţ <}f#I +ASpzv ]k+K 8$VU,mz0V;cFJzY.vխj-J(ĉ ӳA縎 TsgP rH8u0 #G)Lk?~jNx[=5ʕ~$ qSxOtZfY.]z㯮}kaz+&Q7jtt4I-\_ ᩷AYۛA`!Vl_PZZ5Q`8PaJ)%kÝ*[F+#(K{V֊cDx~ktll4 wZ?ev΍㺜s˓Q+%$Rܸqc IDATii\.cr\..t.㸴{B2R0T=û3ϏXݹf:>AJ\i=*ke8j,( &뢮ʃ"oNHz,W1 ~V> ǪhJ?>W+4r:Qq|t4:~ui5j,RF[ĸ:N}6еk׮mllBP(,>|_-IJkՂdAW8i(bqRl <5a&&+=p^R=cNyU9O;ӷ"$ +J$AJ :UhVF+ݻЛճ scSSs绝=3֮Z]8ai7MZnTܹS* \.g5;/3#aLbǩUE3tMb4JkNņ y>za$ҿ'; ogv.`$(t>FTj9Ii ?W6qܡsR7޼~횡lO%1%L.NkGV ]__wVVV:ꉎ8q!  ICO{5ק}21ft|re8Ն8+U9<.QB3CJǖc (@MDSx`sTGBlYTJ7oƏ׾ѣ 9&z>I ]_UQPq8 Szu7_(p7}ovpz: -лݖqufij%UHZi8s<|? s\> m)J)/jRZ.U֔RA`(yta-k\ Ӧ~28l{[˳': lIZpo\3~ڇؾxN_1̳a[am5vpΟ=qDʸzAڪYhժT*V+AY[[ja"P j鮕-֎aת-mЄiTWp\(}Jk<(]r]];҇U@.%R8uNcu9Fj-//ommZ-BH###?yG iP0 CLStQ=5G40W׸obC) u\-voƩ%"}hSpWSJQb j38q(:3ڏզVՑdبB cڵk7o*6~n@sԑ#'^rE)5::Nc`u?zt"BXcqOf]f}$\1}ww\.Hݽ{nݺSӨ!tzz:sFJ"ntttll ({{{|&JiG<fU } !cJq8;;+١`O{^RQJas~~Bࠈ뺳X-v/xlټvڍ7\׵ U }dI鉿D}JA(w$IEesϛ?vXp}ߟ N-Wֲ|lr|>_*pHKKK>ʎ#yжg҅߾bSZ͎ =3$V<8UG3fvdbsp^CeKxh4Z\.! ñ1*!dggwrT>(P%wX, 6=٬`eTsT̞,8SqiQ(Kj4fX=rNk@ټz9ccc֣<UQFNfOhGvqePXYVؘ(!4qmMz4D`0Q A?(zfBJiE>D2q۔)W49=z|pvףz9׾=А tW/iuŮUؠ͓abqǎ_s+-:Cv/ ,+&L&9 @wQq, WB(7PMH$FcLji/^VRetNJ)1Lij0 F~J'nb~i0\PP@tj.$h1a kcIv1GEexb|9{TDoHꪋ̔J%]l ]|]gI+ZBJRCLU&Z7BGhOK"ĺ4='+@Wݯ%-itvDi;XB8&]|Hd zW;XBń>KH)yE3"Ȫuٺ^X(tM 96.M>)/]&*bR-l"DiUCW Ot@W++] `miۏw Bz{{}>t|>}ݽH$Bxn/**:q"tpimmCX?޸q̙3>f066B[p"e,100s^/ŋUUUHaH$z:K9D>} ]7v-ݻhE>;v,<kkk^zICOOOcccaa={A6Ãd2NgUUUJ1\.qvݻwuyMuuuJ#0_|`&///ĭ{$eF;մL&ZXTҖ\!`0L2 r:;;SRR255HP}>=}:Okjj ɹr q_-tI"Zvaa!`FBP(8Vv߾}rgb˗/ +++6?N$,f8j߾}^wyyѣG4Bb*++$!dii n8ϟ8yѣGvөP(ӵ~jLr=ٳgjuWWWss^'\|h4Z]ve>\zUAj;wvuuz0;h%ĕeu:q~~h4g8vnn@4 ?xj:>,Ųq֭o߾xo=귓}}}eee& W] &] t@Wt+]#z?IENDB`cadabra-1.39/osx/dylibbundler/index.html000066400000000000000000000161231234107666300203230ustar00rootroot00000000000000 SourceForge.net Logo

New! Captain MacLib QuickLook plugin


 
     Use this simple Quicklook plugin to instantly get info about any library/executable, including architectures and dependencies.
  • Download CaptainMacLib v0.1 now
  • Get the source code
  • mac dylib bundler

    About

    Mac OS X intoduced an innovative and very useful way to package applications : app bundles. While their design has all that is needed to ease distribution of resources and frameworks, it seems like dynamic libraries (.dylib) are very complicated to distribute. Sure, applications developped specifically for OS X won't make use of them, however applications ported from Linux or other Unices may have dependencies that will only compile as dylibs. By default, there exists no mecanism to bundle them but some command-line utilities provided by Apple - however it turns out that for a single program it is often necessary to issue dozens of commands! This often leads each porter to develop their own "home solution" wich are often hacky, poorly portable and/or unoptimal.

    dylibbundler is a small command-line programs that aims to make bundling .dylibs as easy as possible. It automatically determines which dylibs are needed by your program, copies these libraries inside the app bundle, and fixes both them and the executable to be ready for distribution... all this with a single command on the teminal! It will also work if your program uses plug-ins that have dependencies too.

    It usually involves 2 actions :
    • Creating a directory (by default called libs) that can be placed inside the Contents folder of the app bundle.
    • Fixing the executable file so that it is aware of the new location of its dependencies.

    Download

    Download version 0.4.4 now
    dylibbundler is not yet considered stable but already usable.
    Note that version 0.3 is not compatible with version 0.25, as it makes no more use of config files and the terminal syntax has changed a little.

    Installation

    In the terminal, cd to the main directory of dylibbundler and type "make". You can install with "sudo make install".

    Feedback / Contact

    You can contact me at auria@users.sourceforge.net or on the sourceforge project page

    Using dylibbundler on the terminal

    Here is a list of flags you can pass to dylibbundler on the terminal.

    -h, --help
    displays a summary of options
    -x, --fix-file (executable or plug-in filepath)
    Fixes given executable or plug-in file (a .dylib can work too. anything on which 'otool -L' works is accepted by -x). Dylibbundler will walk through the dependencies of the specified file to build a dependency list. It will also fix the said files' dependencies so that it expects to find the libraries relative to itself (e.g. in the app bundle) instead of at an absolute path (e.g. /usr/local/lib). To pass multiple files to fix, simply specify multiple -x flags.
    -b, --bundle-deps
    Copies libaries to a local directory, fixes their internal name so that they are aware of their new location, fixes dependencies where bundled libraries depend on each other. If this option is not passed, no libraries will be prepared for distribution.
    -i, --ignore (path)
    Dylibs in (path) will be ignored. By default, dylibbundler will ignore libraries installed in /usr/lib since they are assumed to be present by default on all OS X installations. (It is usually recommend not to install additional stuff in /usr/, always use /usr/local/ or another prefix to avoid confusion between system libs and libs you added yourself)
    -d, --dest-dir (directory)
    Sets the name of the directory in wich distribution-ready dylibs will be placed, relative to the current working directory. (Default is ./libs) For an app bundle, it is often conveniant to set it to something like ./MyApp.app/Contents/libs.
    -p, --install-path (libraries install path)
    Sets the "inner" installation path of libraries, usually inside the bundle and relative to executable. (Default is @executable_path/../libs/, which points to a directory named libs inside the Contents directory of the bundle.)
    The difference between -d and -p is that -d is the location dylibbundler will put files at, while -p is the location where the libraries will be expected to be found when you launch the app. Both are often related.

    -of, --overwrite-files
    When copying libraries to the output directory, allow overwriting files when one with the same name already exists.
    -od, --overwrite-dir
    If the output directory already exists, completely erase its current content before adding anything to it. (This option implies --create-dir)
    -cd, --create-dir
    If the output directory does not exist, create it.
    A command may look like
    % dylibbundler -od -b -x ./HelloWorld.app/Contents/MacOS/helloworld -d ./HelloWorld.app/Contents/libs/
    
    If you want to create a universal binary by merging toghether two builds from PPC and Intel machines, you can ease it up by putting the ppc and intel libs in different directories, then to create the universal binary you only have to lipo the executable.
    % dylibbundler -od -b -x ./HelloWorld.app/Contents/MacOS/helloworld
        -d ./HelloWorld.app/Contents/libs-ppc/ -p @executable_path/../libs-ppc/
    
    % dylibbundler -od -b -x ./HelloWorld.app/Contents/MacOS/helloworld
        -d ./HelloWorld.app/Contents/libs-intel/ -p @executable_path/../libs-intel/
    








    cadabra-1.39/osx/dylibbundler/maclib.jpg000066400000000000000000000243161234107666300202620ustar00rootroot00000000000000JFIF,,LEAD Technologies Inc. V1.01C  !"$"$C B!1A"Qaq2B#R$b%3CScrs ?]@(7VVoݼ-mN B$Lc7MxMͫ,)n#o?'GǦ[e1kD6ڦ'h.L\C%H2<E:@(PP @t@${  -ߩǿf6`HOmD}J .L7Ԑ}( f\UÎ)${o?΂W;cӣ1|M lH'qAG.eV}=\:)VSv BDrǤ:+8\m-[zFTm$1P ڀP @(P 3B\N]\mnKBFX>W+vo]VЅ)N 'n$ kp%Djؒ@%@j$(OYxc ObN?CoGĥ@P7$zkh h5nne'J2=4|j,>e8- =F#P+h}f^}ӥVMGזI6s-BM򂏪! j q׏qV_HZcj+DRPf(3ށBH#x4'ASο~ k#~rh`P<#@Ao=vUZs[v j Ʋx*$(:y\b9)R܂6=M)+q-W ~m0&}fVܕtnIPPVGuO[IXٷMǔe AI'Ijzyi*N Ls@znq͡BR.P{4dʱXBRe$0$܊ =|S&Wm-^qh%’w3At~xt&Riwypp4tO) =<#oo" 4P(@@o@h86pY lڹIlzZ_:G;9Lu?k7P{9Om'Pd> MmۅLZcR9&gf=ol1܂ soWunFⒽ)IQJ{#0$%p-GJXYh;zk> i 77)ӤjBH},y8z2oe[X4$=M?'8$ #HU<̟^fuR9~= nm@埈Ukl2< v::pZLw;#x U$kais{zե.ؤ4Pթ-FJB3>Ŝxo 7,7~Z Pt*@204lXՆE0j -S &UyDϵށhڀ'z |U]ve%KopD`yd@`gA7/w3kvڒR.60O}wPe:WW|CIոAfۛhImY&edz6tm ձʃ%Kmب$GP>Au:ˮ~YXԕ,i9# yc0wMڮI %cPd==d˝?kqnAq gAmj g+CRWxz?-%nOj:nuai<^Sn$8<v0΁)#rh6$o@ P9?j Ǟ鎆v.2Tԥ A v՘ˆ-֖R$`+TvDo3f.1)ƶ%lT̥$ʽpX%%KQ6o[g d)#RX/Yy*"S; "꜕vRwgh= éHY&,Þ}TA0͟81W9)KA$ ѽ]8ΗKIC,%+Rj %˟ْ )\pD1}ַH e$ae-E<qT$H(;-#Ş$WL\:TCp-w8cCg-ӌaRSjB\̒"6397+CY'cy6fD;teWy0ͱԙw~, عA J:cmO'f)(3v G;Gcn9Pj6mܣDIP'؊_ vA74s@57sA俀YEK/:A J@*΃ ֲY7$|3xY+mlBqP_8L؆YjRvP)~cmع?EŴI$ #&3mʲt>/P Q+A z3exmUA<םPA AI.8PAjWRtO֯Xt6-\-ʣrT n1qkV^yujC %6 $n(+>\ @JE~[n[ aPBA4m-WisdYYK>դ3'z,XH@Jq&Ju; [:/fFB)}^+şMG<;,EaԂI'{u ۾a@ w?izun+'Wkn啸m:.Q DzӡX1k cBԇ< dL@ :0]37Lj۹J CJJJL3&GK )6z {=wrRl-I}?== -az*ᴼm &FldsΔ>N"쳒Krm|–r N}*1>Q $u7Vu27.w .[$-N#6o.ܼ.2=P9aPVneM낞!Co~ ۥ}ud!)icWT8Ć<*;vE-қq2 yqAPJo4گ U. ~,r,[4ę?*9+uLWQGqC{lo ish8I0b`j "6 AX޽- 庋I>7Kvnf]((d-STx\PRlkKw\PR/3xie9ѵ@ qOz תqv m` cx=:[w(RAg @ͼYS%B*$h y:m\7!æZҡ rF_jN_ݽŠv݈=w?RtKscrUŹ%*RD=c%yLC'\2/ĕu@#*Cv%j֘iy!$+$BkJ$~+27 )5"]B ,4Bb~>@@gނ?5do-YXny=R~κt)YNN}A-J[ҟȾRx#A98/7pma*2AEխy8WbZ@QRfAp p%.͐`=hI@ j?(:tO`^p.Bt7nҖP?$ ~Htb|,L۱fWO(%I÷.PIp)'T-+AvAeaV7[}MydI H~'|®1WJCwIm!D ނQxQmQ:9Nl@Jj↨H$)!B9 }}uRۈ2@A UxRJtD""h"/QswjRKA H)R ܈PGa͋ql,-GQqnH)$VcAԎlڼ~ .XiP2(QAu&G[4V@R-hV2Qca«YI-_h%*( Ҁ3/ì Tūi׷0̀͵VQfF@Lc}OOڼmѤҒx``4k,;[6o\;oxĄRI jHJ;T;A{R_ WIh u Re*؈I.m)1xdd9'ۭ%NDm> m7?ƃ+Q(%* WX(#iPHҁ,cKANq҂Q,)ARV[#v{y.:#}AKպ/hA bJ[uv*qAuN^^)焝+Q0vv#-nl:~.Kn:C,$-؍CDGA/cӷ)J}} ! O?PQN(%-X%0J'n6&?'h9aLJ ڃ%CpRQ}!a%JC3;) 蟐~@ w|뜚B 6̭gh)PdȰIPS=Z@#w!t­1=Zw} ,kcśЗi->-; q$!t-oa<QAeW% $=pb튐Z-)&eI1`#o@ݣǗmhU-#Z"Lv46J5oXzTHyRd|h 7m,nUhi! J?#Pt^dinGM\ Ti&?IqZ7jC JBʌ;A]l8TBF@ ٲlWҀÀ2q v3@ BU4-@zzh-0fD{,o@ ABALGCa"q1@t`EīDFhu@w? >ݨ2Fжm| !\O;9*lS2P䍴 H~FS[%ZG?z 4Ըܞ}P>@&@ހm@$G((3 ހPPz5FP4 #ƁDށ]j(y8P @;s@F <cadabra-1.39/osx/dylibbundler/makefile000066400000000000000000000007701234107666300200270ustar00rootroot00000000000000dylibbundler: g++ -c -I./src ./src/Settings.cpp -o ./Settings.o g++ -c -I./src ./src/DylibBundler.cpp -o ./DylibBundler.o g++ -c -I./src ./src/Dependency.cpp -o ./Dependency.o g++ -c -I./src ./src/main.cpp -o ./main.o g++ -c -I./src ./src/Utils.cpp -o ./Utils.o g++ -o ./dylibbundler ./Settings.o ./DylibBundler.o ./Dependency.o ./main.o ./Utils.o clean: rm -f *.o rm -f ./dylibbundler install: dylibbundler cp ./dylibbundler /usr/local/bin/dylibbundler chmod 775 /usr/local/bin/dylibbundlercadabra-1.39/osx/dylibbundler/src/000077500000000000000000000000001234107666300171125ustar00rootroot00000000000000cadabra-1.39/osx/dylibbundler/src/Dependency.cpp000066400000000000000000000211361234107666300216770ustar00rootroot00000000000000/* 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 "Dependency.h" #include #include #include #include "Utils.h" #include "Settings.h" #include #include #include std::string stripPrefix(std::string in) { return in.substr(in.rfind("/")+1); } //the pathes to search for dylibs, store it globally to parse the environment variables only once std::vector pathes; //initialize the dylib search pathes void initSearchPathes(){ //Check the same pathes the system would search for dylibs std::string searchPathes; char *dyldLibPath = std::getenv("DYLD_LIBRARY_PATH"); if( dyldLibPath!=0 ) searchPathes = dyldLibPath; dyldLibPath = std::getenv("DYLD_FALLBACK_FRAMEWORK_PATH"); if (dyldLibPath != 0) { if (!searchPathes.empty() && searchPathes[ searchPathes.size()-1 ] != ':') searchPathes += ":"; searchPathes += dyldLibPath; } dyldLibPath = std::getenv("DYLD_FALLBACK_LIBRARY_PATH"); if (dyldLibPath!=0 ) { if (!searchPathes.empty() && searchPathes[ searchPathes.size()-1 ] != ':') searchPathes += ":"; searchPathes += dyldLibPath; } if (!searchPathes.empty()) { std::stringstream ss(searchPathes); std::string item; while(std::getline(ss, item, ':')) { if (item[ item.size()-1 ] != '/') item += "/"; pathes.push_back(item); } } } // if some libs are missing prefixes, this will be set to true // more stuff will then be necessary to do bool missing_prefixes = false; Dependency::Dependency(std::string path) { // check if given path is a symlink std::string cmd = "readlink -n " + path; const bool is_symlink = system( (cmd+" > /dev/null").c_str())==0; if (is_symlink) { char original_file_buffer[PATH_MAX]; std::string original_file; if(path[path.size()-1]==' ') path=path.substr(0,path.size()-1); if (not realpath(path.c_str(), original_file_buffer)) { std::cerr << "\n/!\\ WARNING : Cannot resolve symlink '" << path.c_str() << "' " << errno << std::endl; original_file = path; } else { original_file = original_file_buffer; } //original_file = original_file.substr(0, original_file.find("\n") ); filename = stripPrefix(original_file); prefix = path.substr(0, path.rfind("/")+1); addSymlink(path); } else { filename = stripPrefix(path); prefix = path.substr(0, path.rfind("/")+1); } //check if the lib is in a known location if( !prefix.empty() && prefix[ prefix.size()-1 ] != '/' ) prefix += "/"; if( prefix.empty() || !fileExists( prefix+filename ) ) { //the pathes contains at least /usr/lib so if it is empty we have not initilazed it if( pathes.empty() ) initSearchPathes(); //check if file is contained in one of the pathes for( size_t i=0; i> buffer; prefix = buffer; std::cout << std::endl; if(prefix.compare("quit")==0) exit(1); if( !prefix.empty() && prefix[ prefix.size()-1 ] != '/' ) prefix += "/"; if( !fileExists( prefix+filename ) ) { std::cerr << (prefix+filename) << " does not exist. Try again" << std::endl; continue; } else { pathes.push_back( prefix ); std::cerr << (prefix+filename) << " was found. /!\\MANUALLY CHECK THE EXECUTABLE WITH 'otool -L', DYLIBBUNDLDER MAY NOT HANDLE CORRECTLY THIS UNSTANDARD/ILL-FORMED DEPENDENCY" << std::endl; break; } } } //new_name = filename.substr(0, filename.find(".")) + ".dylib"; new_name = filename; } void Dependency::print() { std::cout << std::endl; std::cout << " * " << filename.c_str() << " from " << prefix.c_str() << std::endl; const int symamount = symlinks.size(); for(int n=0; n " << symlinks[n].c_str() << std::endl;; } std::string Dependency::getInstallPath() { return Settings::destFolder() + new_name; } std::string Dependency::getInnerPath() { return Settings::inside_lib_path() + new_name; } void Dependency::addSymlink(std::string s){ symlinks.push_back(stripPrefix(s)); } // comapres the given Dependency with this one. If both refer to the same file, // it returns true and merges both entries into one. bool Dependency::mergeIfSameAs(Dependency& dep2) { if(dep2.getOriginalFileName().compare(filename) == 0) { const int samount = dep2.getSymlinkAmount(); for(int n=0; n #include class Dependency { // origin std::string filename; std::string prefix; std::vector symlinks; // installation std::string new_name; public: Dependency(std::string path); void print(); std::string getOriginalFileName() const{ return filename; } std::string getOriginalPath() const{ return prefix+filename; } std::string getInstallPath(); std::string getInnerPath(); void addSymlink(std::string s); int getSymlinkAmount() const{ return symlinks.size(); } std::string getSymlink(const int i) const{ return symlinks[i]; } std::string getPrefix() const{ return prefix; } void copyYourself(); void fixFileThatDependsOnMe(std::string file); // comapres the given Dependency with this one. If both refer to the same file, // it returns true and merges both entries into one. bool mergeIfSameAs(Dependency& dep2); }; #endifcadabra-1.39/osx/dylibbundler/src/DylibBundler.cpp000066400000000000000000000136561234107666300222100ustar00rootroot00000000000000/* 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 "DylibBundler.h" #include #include #include "Utils.h" #include "Settings.h" #include "Dependency.h" std::vector deps; void changeLibPathsOnFile(std::string file_to_fix) { std::cout << "\n* Fixing dependencies on " << file_to_fix.c_str() << std::endl; const int dep_amount = deps.size(); for(int n=0; n& lines) { // execute "otool -L" on the given file and collect the command's output std::string cmd = "otool -L " + filename; std::string output = system_get_output(cmd); if(output.find("can't open file")!=std::string::npos or output.find("No such file")!=std::string::npos or output.size()<1) { std::cerr << "Cannot find file " << filename << " to read its dependencies" << std::endl; exit(1); } // split output tokenize(output, "\n", &lines); } void collectDependencies(std::string filename) { std::vector lines; collectDependencies(filename, lines); std::cout << "."; fflush(stdout); const int line_amount = lines.size(); for(int n=0; n lines; collectDependencies(deps[n].getOriginalPath(), lines); const int line_amount = lines.size(); for(int n=0; n void collectDependencies(std::string filename); void collectSubDependencies(); void doneWithDeps_go(); #endifcadabra-1.39/osx/dylibbundler/src/Settings.cpp000066400000000000000000000053141234107666300214210ustar00rootroot00000000000000/* 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 "Settings.h" #include namespace Settings { bool overwrite_files = false; bool overwrite_dir = false; bool create_dir = false; bool canOverwriteFiles(){ return overwrite_files; } bool canOverwriteDir(){ return overwrite_dir; } bool canCreateDir(){ return create_dir; } void canOverwriteFiles(bool permission){ overwrite_files = permission; } void canOverwriteDir(bool permission){ overwrite_dir = permission; } void canCreateDir(bool permission){ create_dir = permission; } bool bundleLibs_bool = false; bool bundleLibs(){ return bundleLibs_bool; } void bundleLibs(bool on){ bundleLibs_bool = on; } std::string dest_folder_str = "./libs/"; std::string destFolder(){ return dest_folder_str; } void destFolder(std::string path) { dest_folder_str = path; // fix path if needed so it ends with '/' if( dest_folder_str[ dest_folder_str.size()-1 ] != '/' ) dest_folder_str += "/"; } std::vector files; void addFileToFix(std::string path){ files.push_back(path); } int fileToFixAmount(){ return files.size(); } std::string fileToFix(const int n){ return files[n]; } std::string inside_path_str = "@executable_path/../libs/"; std::string inside_lib_path(){ return inside_path_str; } void inside_lib_path(std::string p) { inside_path_str = p; // fix path if needed so it ends with '/' if( inside_path_str[ inside_path_str.size()-1 ] != '/' ) inside_path_str += "/"; } std::vector prefixes_to_ignore; void ignore_prefix(std::string prefix) { if( prefix[ prefix.size()-1 ] != '/' ) prefix += "/"; prefixes_to_ignore.push_back(prefix); } bool isPrefixBundled(std::string prefix) { if(prefix.find(".framework") != std::string::npos) return false; if(prefix.find("@executable_path") != std::string::npos) return false; if(prefix.compare("/usr/lib/") == 0) return false; const int prefix_amount = prefixes_to_ignore.size(); for(int n=0; n namespace Settings { bool isPrefixBundled(std::string prefix); void ignore_prefix(std::string prefix); bool canOverwriteFiles(); void canOverwriteFiles(bool permission); bool canOverwriteDir(); void canOverwriteDir(bool permission); bool canCreateDir(); void canCreateDir(bool permission); bool bundleLibs(); void bundleLibs(bool on); std::string destFolder(); void destFolder(std::string path); void addFileToFix(std::string path); int fileToFixAmount(); std::string fileToFix(const int n); std::string inside_lib_path(); void inside_lib_path(std::string p); } #endifcadabra-1.39/osx/dylibbundler/src/Utils.cpp000066400000000000000000000114641234107666300207240ustar00rootroot00000000000000/* 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 "Utils.h" #include "Dependency.h" #include "Settings.h" #include #include #include #include #include #include using namespace std; /* void setInstallPath(string loc) { path_to_libs_folder = loc; }*/ void tokenize(const string& str, const char* delim, vector* vectorarg) { vector& tokens = *vectorarg; string delimiters(delim); // skip delimiters at beginning. string::size_type lastPos = str.find_first_not_of( delimiters , 0); // find first "non-delimiter". string::size_type pos = str.find_first_of(delimiters, lastPos); while (string::npos != pos || string::npos != lastPos) { // found a token, add it to the vector. tokens.push_back(str.substr(lastPos, pos - lastPos)); // skip delimiters. Note the "not_of" lastPos = str.find_first_not_of(delimiters, pos); // find next "non-delimiter" pos = str.find_first_of(delimiters, lastPos); } } bool fileExists( std::string filename ) { if (access( filename.c_str(), F_OK ) != -1) { return true; // file exists } else { //std::cout << "access(filename) returned -1 on filename [" << filename << "] I will try trimming." << std::endl; std::string delims = " \f\n\r\t\v"; std::string rtrimmed = filename.substr(0, filename.find_last_not_of(delims) + 1); std::string ftrimmed = rtrimmed.substr(rtrimmed.find_first_not_of(delims)); if (access( ftrimmed.c_str(), F_OK ) != -1) { return true; } else { //std::cout << "Still failed. Cannot find the specified file." << std::endl; return false;// file doesn't exist } } } void fixLibDependency(string old_lib_path, string new_lib_name, string target_file_name) { string command = string("install_name_tool -change ") + old_lib_path + string(" ") + Settings::inside_lib_path() + new_lib_name + string(" ") + target_file_name; if( systemp( command ) != 0 ) { cerr << "\n\nError : An error occured while trying to fix depency of " << old_lib_path << " in " << target_file_name << endl; exit(1); } } void copyFile(string from, string to) { bool override = Settings::canOverwriteFiles(); if(!override) { if(fileExists( to )) { cerr << "\n\nError : File " << to.c_str() << " already exists. Remove it or enable overriding." << endl; exit(1); } } string override_permission = string(override ? "-f " : "-n "); // copy file to local directory string command = string("cp ") + override_permission + from + string(" ") + to; if( systemp( command ) != 0 ) { cerr << "\n\nError : An error occured while trying to copy file " << from << " to " << to << endl; exit(1); } // give it write permission string command2 = string("chmod +w ") + to; if( systemp( command2 ) != 0 ) { cerr << "\n\nError : An error occured while trying to set write permissions on file " << to << endl; exit(1); } } std::string system_get_output(std::string cmd) { FILE * command_output; char output[128]; int amount_read = 1; std::string full_output; try { command_output = popen(cmd.c_str(), "r"); if(command_output == NULL) throw; while(amount_read > 0) { amount_read = fread(output, 1, 127, command_output); if(amount_read <= 0) break; else { output[amount_read] = '\0'; full_output += output; } } } catch(...) { std::cerr << "An error occured while executing command " << cmd.c_str() << std::endl; pclose(command_output); return ""; } int return_value = pclose(command_output); if(return_value != 0) return ""; return full_output; } int systemp(std::string& cmd) { std::cout << " " << cmd.c_str() << std::endl; return system(cmd.c_str()); } cadabra-1.39/osx/dylibbundler/src/Utils.h000066400000000000000000000023111234107666300203600ustar00rootroot00000000000000/* 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 _utils_h_ #define _utils_h_ #include #include class Library; void tokenize(const std::string& str, const char* delimiters, std::vector*); bool fileExists( std::string filename ); void copyFile(std::string from, std::string to); // executes a command in the native shell and returns output in string std::string system_get_output(std::string cmd); // like 'system', runs a command on the system shell, but also prints the command to stdout. int systemp(std::string& cmd); #endifcadabra-1.39/osx/dylibbundler/src/main.cpp000066400000000000000000000114021234107666300205400ustar00rootroot00000000000000/* 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 #include #include #include #include "Settings.h" #include "Utils.h" #include "DylibBundler.h" /* TODO - what happens if a library is not remembered by full path but only name? (support improved, still not perfect) - could get mixed up if symlink and original are not in the same location (won't happen for UNIX prefixes like /usr/, but in random directories?) FIXME: why does it copy plugins i try to fix to the libs directory? */ const std::string VERSION = "0.4.1"; // FIXME - no memory management is done at all (anyway the program closes immediately so who cares?) std::string installPath = ""; void showHelp() { std::cout << "dylibbundler " << VERSION << std::endl; std::cout << "dylibbundler is a utility that helps bundle dynamic libraries inside mac OS X app bundles.\n" << std::endl; std::cout << "-x, --fix-file " << std::endl; std::cout << "-b, --bundle-deps" << std::endl; std::cout << "-d, --dest-dir " << std::endl; std::cout << "-p, --install-path <'inner' path of bundled libraries (usually relative to executable, by default '@executable_path/../libs/')>" << std::endl; std::cout << "-of, --overwrite-files (allow overwriting files in output directory)" << std::endl; std::cout << "-od, --overwrite-dir (totally overwrite output directory if it already exists. implies --create-dir)" << std::endl; std::cout << "-cd, --create-dir (creates output directory if necessary)" << std::endl; std::cout << "-i, --ignore (will ignore libraries in this directory)" << std::endl; std::cout << "-h, --help" << std::endl; } int main (int argc, char * const argv[]) { // parse arguments for(int i=0; i0) { // if we meet an unknown flag, abort // ignore first one cause it's usually the path to the executable std::cerr << "Unknown flag " << argv[i] << std::endl << std::endl; showHelp(); exit(1); } } if(not Settings::bundleLibs() and Settings::fileToFixAmount()<1) { showHelp(); exit(0); } std::cout << "* Collecting dependencies"; fflush(stdout); const int amount = Settings::fileToFixAmount(); for(int n=0; n" > defaults.cc # echo -n "std::string defaults=\"" >> defaults.cc # cat defaults | tr '\n' '<' | sed -e 's/\\/\\\\/g' | sed -e 's/> defaults.cc # echo "\";" >> defaults.cc # @CXX@ -c -o defaults.o defaults.cc test_tree: test_tree.o @CXX@ -o test_tree test_tree.o test_lie: test_lie.o modules/lie.o ifeq ($(strip $(MACTEST)),) @CXX@ -o test_lie test_lie.o modules/lie.o `pkg-config --libs modglue` else @CXX@ -o test_lie test_lie.o modules/lie.o `pkg-config --libs modglue` endif tree_regression_tests: tree_regression_tests.o @CXX@ -o tree_regression_tests tree_regression_tests.o #test_xperm: test_xperm.o modules/xperm_new.o # @CXX@ -o test_xperm test_xperm.o modules/xperm_new.o tree_example: tree_example.o tree.hh @CXX@ -o tree_example tree_example.o test_combinatorics: test_combinatorics.o combinatorics.o @CXX@ -o test_combinatorics test_combinatorics.o combinatorics.o test_young: test_young.o youngtab.o combinatorics.o @CXX@ -o test_young test_young.o youngtab.o combinatorics.o ${LDFLAGS} -lgmpxx -lgmp test_preprocessor: test_preprocessor.o preprocessor.o @CXX@ -o test_preprocessor test_preprocessor.o preprocessor.o ${LDFLAGS} -lgmpxx -lgmp mpi_pass_tree: mpi_pass_tree.o @CXX@ -o mpi_pass_tree mpi_pass_tree.o -L/usr/lib/mpich/lib -lmpich++ -lpmpich -lmpich mpi_remote_run.o: mpi_remote_run.cc mpiCC -c -o mpi_remote_run.o mpi_remote_run.cc mpi_remote_run: mpi_remote_run.o mpiCC -o mpi_remote_run mpi_remote_run.o #test_parser: test_parser.o storage.o parser.o preprocessor.o display.o # @CXX@ -o test_parser test_parser.o storage.o parser.o preprocessor.o display.o modules/properties.o algorithm.o -lgmpxx test_gmp: test_gmp.o @CXX@ -o test_gmp test_gmp.o ${LDFLAGS} -lgmpxx -lgmp # The 2nd generation parser. # First the lexx/yacc bit. parser2.tab.h parser2.tab.c: parser2.y bison -v -d parser2.y lex.yy.c: parser2.l parser2.tab.h flex -o lex.yy.c parser2.l # Then the actual compilation. lex.yy.o: lex.yy.c parser2.tab.h @CXX@ -c -o lex.yy.o lex.yy.c parser2.tab.o: parser2.tab.c @CXX@ -c -o parser2.tab.o parser2.tab.c parser2: parser2.tab.o lex.yy.o storage.o props.o @CXX@ -o parser2 $+ -ll -ly -lgmpxx -lgmp -lpcrecpp # Installation and cleanup. install: ifeq ($(strip $(MACTEST)),) strip cadabra endif # strip -S cadabra #endif @INSTALL@ -m 0755 -d ${DESTDIR}@prefix@/bin @INSTALL@ -m 0755 cadabra ${DESTDIR}@prefix@/bin uninstall: rm -f @prefix@/bin/cadabra # rm -f @prefix@/include/tree.hh clean: rm -f *.o *~ cadabra cadabra_static test_tree test_combinatorics test_preprocessor test_parser test_gmp tree_example test_young tree_regression_tests test_lie test_xperm rm -f parser2.output parser2.tab.c parser2.tab.h lex.yy.cc lex.yy.c ( cd modules; $(MAKE) clean ) distclean: clean rm -f Makefile out cdb.log result .depend gprof.out ( cd modules; $(MAKE) distclean ) .depend: rm -f .depend for i in ${SRCS}; \ do @CXX@ ${MCFLAGS} -E -MM -MT `echo $$i | sed -e 's/\.\///' -e 's/\.cc/\.o/'` ${CFLAGS} $$i >> .depend; \ done include .depend cadabra-1.39/src/algorithm.cc000066400000000000000000001636471234107666300161400ustar00rootroot00000000000000/* Cadabra: a field-theory motivated computer algebra system. Copyright (C) 2001-2011 Kasper Peeters 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 3 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, see . */ #include "algorithm.hh" #include "display.hh" #include "storage.hh" #include "props.hh" #include "modules/dummies.hh" #include "modules/algebra.hh" #include "modules/field_theory.hh" #include #include stopwatch algorithm::index_sw; stopwatch algorithm::get_dummy_sw; consistency_error::consistency_error(const std::string& str) : logic_error(str) { } algorithm_interrupted::algorithm_interrupted() : logic_error("Ctrl-C pressed") { } algorithm_interrupted::algorithm_interrupted(const std::string& str) : logic_error("Ctrl-C pressed while executing "+str) { } active_node::active_node(exptree& tr_, iterator it_) : this_command(it_), tr(tr_), args_begin_(tr_.end()), args_end_(tr_.end()) { } exptree::sibling_iterator active_node::args_begin() const { if(args_begin_==tr.end() && this_command!=tr.end()) { args_begin_=tr.begin(this_command); args_end_ =tr.end(this_command); if(args_begin_!=args_end_) { if(args_begin_->fl.bracket==str_node::b_round || args_begin_->fl.bracket==str_node::b_square) ++args_begin_; } } return args_begin_; } exptree::sibling_iterator active_node::args_end() const { args_begin(); return args_end_; } unsigned int active_node::number_of_args() const { sibling_iterator it=args_begin(); unsigned int ret=0; while(it!=args_end()) { ++ret; ++it; } return ret; } bool active_node::has_argument(const std::string& arg) const { sibling_iterator sit=args_begin(); while(sit!=args_end()) { if(*sit->name==arg) return true; ++sit; } return false; } algorithm::constructor_error::constructor_error() { } algorithm::algorithm(exptree& tr_, iterator it_) : active_node(tr_, it_), expression_modified(false), equation_number(0), global_success(g_not_yet_started), number_of_calls(0), number_of_modifications(0), suppress_normal_output(false), discard_command_node(false), eo(0) { } algorithm::~algorithm() { } bool algorithm::is_output_module() const { return false; } //bool algorithm::can_apply(iterator it) // { // if(tr.begin(it)!=tr.end(it)) // return can_apply(tr.begin(it), tr.end(it)); // else return false; // } //bool algorithm::can_apply(sibling_iterator st, sibling_iterator nd) // { // while(st!=nd) { // if(can_apply(st)) return true; // ++st; // } // return false; // } //algorithm::result_t algorithm::apply(iterator& it) // { // // This will be called when acting recursively or pointwise, yet the // // algorithm only implements range operations. // // sibling_iterator st=tr.begin(it); // sibling_iterator nd=tr.end(it); // return apply(st, nd); // } // //algorithm::result_t algorithm::apply(sibling_iterator& st, sibling_iterator& nd) // { // // This will be called when acting on a mark but the algorithms // // implements only node-wise operations. // // // FIXME: fix this, does not work yet (handle error conditions). // result_t retval=l_error; // sibling_iterator sbb=st; // while(sbb!=nd) { // iterator backup=sbb; // retval=apply(backup); // if(sbb==st) // st=backup; // sbb=backup; // ++sbb; // } // return retval; // } // The entry point called by manipulator.cc void algorithm::apply(unsigned int lue, bool multiple, bool until_nochange, bool make_copy, int act_at_level, bool called_by_manipulator) { if(called_by_manipulator) { report_progress_stopwatch.stop(); report_progress_stopwatch.reset(); } last_used_equation_number=lue; expression_modified=false; iterator actold=tr.end(); iterator acton=tr.end(); subtree=tr.end(); // Figure out on which subtree the algorithm is supposed to act. if(tr.number_of_children(this_command)>=1) { iterator chld=tr.begin(this_command); if(chld->fl.bracket==str_node::b_round && *this_command->name!="@") { // all normal commands actold=tr.equation_by_number_or_name(chld, last_used_equation_number, equation_number); global_success=g_arguments_accepted; if(actold==tr.end()) { throw consistency_error("Expression (" +tr.equation_number_or_name(chld, last_used_equation_number) +") does not exist."); return; } else global_success=g_operand_determined; } else if(chld->fl.bracket==str_node::b_round && *this_command->name=="@") { // exception for '@(1)' equation_number=lue; global_success=g_operand_determined; acton=chld; } else if(chld->fl.bracket==str_node::b_square) { global_success=g_operand_determined; acton=chld; // if(chld->fl.bracket==str_node::b_square) // chld->fl.bracket=str_node::b_none; // otherwise the square brackets stay forever } else { txtout << "applying algorithm on marks (if any)." << std::endl; } } // Depending on the outcome, different actions should be taken to copy the // original tree and store the result. bool is_output_module=this->is_output_module(); //dynamic_cast(this); if(actold!=tr.end()) { // act on an existing expression previous_expression=tr.named_parent(tr.active_expression(actold), "\\expression"); if(!is_output_module && make_copy) copy_expression(previous_expression); actold=tr.active_expression(actold); if(multiple) { // debugout << "acting with " << *(this_command->name) << " multiple." << std::endl; subtree=actold; apply_recursive(subtree, true, act_at_level, called_by_manipulator, until_nochange); } else { // debugout << "acting with " << *(this_command->name) << " single." << std::endl; subtree=tr.begin(actold); if(can_apply(subtree)) { ++number_of_calls; report_progress((*this_command->name).substr(1, (*this_command->name).size()-2), 0,0,1); result_t res=apply(subtree); if(expression_modified) { ++number_of_modifications; global_success=g_applied; // debugout << "**** " << std::endl; // tr.print_recursive_treeform(debugout, tr.begin()); // debugout << "==== " << std::endl; if(getenv("CDB_PARANOID")) check_consistency(tr.named_parent(subtree,"\\expression")); } else if(is_output_module && res==l_applied) global_success=g_applied; if(res==l_error) global_success=g_apply_failed; } } if(!is_output_module) { if(global_success==g_apply_failed) { if(make_copy) { cancel_modification(); } subtree=previous_expression; } } discard_command_node=true; } else if(acton!=tr.end()) { // act on argument subtree=acton; if(multiple) { apply_recursive(subtree, true, act_at_level, called_by_manipulator, until_nochange); } else { if(can_apply(subtree)) { global_success=g_operand_determined; ++number_of_calls; report_progress((*this_command->name).substr(1, (*this_command->name).size()-2), 0,0,1); apply(subtree); } } if(is_output_module) global_success=g_applied; // txtout << *this_command->name << " completed, " << (subtree!=tr.end()) << " " // << expression_modified << std::endl; if(/* expression_modified && */ subtree!=tr.end()) { // even if expr. not modified, keep original global_success=g_applied; check_consistency(tr.named_parent(subtree,"\\expression")); multiply(subtree->multiplier, *this_command->multiplier); subtree->fl.bracket=this_command->fl.bracket; subtree->fl.parent_rel=this_command->fl.parent_rel; // Rename dummy indices in the replacement to avoid clashes rename_replacement_dummies(subtree, true); // Then safely replace. First remove all children of the command // node which are not the replacement subtree. sibling_iterator sibrem=tr.begin(this_command); while(sibrem!=tr.end(this_command)) { if(sibrem!=subtree) sibrem=tr.erase(sibrem); else ++sibrem; } // Now flatten the tree at the node. tr.flatten(this_command); tr.erase(this_command); // SOMETHING IS WRONG WITH ARGUMENT STUFF. // subtree=tr.replace(this_command,thiscp,subtree,citp); // There are various situations which need to be cleaned up, but can only be handled // here because algorithms themselves are not allowed to modify the tree above the // entry point. The cases are a) nested products, b) numerical factors in products, // c) one to the power something, d) numerical factors on sum nodes, e) nested sums. if(*subtree->name=="\\prod") { if(*tr.parent(subtree)->name=="\\prod") { multiply(tr.parent(subtree)->multiplier, *subtree->multiplier); tr.flatten(subtree); subtree=tr.erase(subtree); } } else { if(*tr.parent(subtree)->name=="\\prod") { if(*subtree->multiplier!=1) { multiply(tr.parent(subtree)->multiplier, *subtree->multiplier); subtree->multiplier=rat_set.insert(1).first; } } // else if(*tr.parent(subtree)->name=="\\pow") { // // FIXME: NOT TRIGGERED? // if(subtree->is_identity()) { // node_one(tr.parent(subtree)); // subtree=tr.parent(subtree); // } // } else if(*subtree->name=="\\sum") { if(*subtree->multiplier!=1) { sibling_iterator sib=tr.begin(subtree); while(sib!=tr.end(subtree)) { multiply(sib->multiplier, *subtree->multiplier); ++sib; } ::one(subtree->multiplier); } if(*tr.parent(subtree)->name=="\\sum") { tr.flatten(subtree); subtree=tr.erase(subtree); } } } discard_command_node=false; } else { discard_command_node=true; subtree=tr.end(); } } // else { // act on marked nodes // if(prepare_for_modification(make_copy)) { // there are marks // sibling_iterator start=marks[0].first; // sibling_iterator end =marks[0].second; // result_t res; // if(can_apply(start, end)) { // ++number_of_calls; // res=apply(start,end); // if(res==l_error) { // cancel_modification(); // subtree=previous_expression; // } // else if(getenv("CDB_PARANOID")) // check_consistency(tr.named_parent(subtree,"\\expression")); // } // else { // cancel_modification(); // subtree=previous_expression; // } // } // else { // no marks // // debugout << "no marks" << std::endl; // iterator dummy=tr.end(); // ++number_of_calls; // if( can_apply(dummy) ) { // result_t res=apply(dummy); // if(is_output_module || res!=l_error) // global_success=g_applied; // } // } // discard_command_node=true; // } if(is_output_module) { suppress_normal_output=true; } } // Returns whether the algorithm has applied at least once. // bool algorithm::apply_recursive(exptree::iterator& st, bool check_cons, int act_at_level, bool called_by_manipulator, bool until_nochange) { assert(tr.is_valid(st)); assert(st!=tr.end()); unsigned long count=0; bool atleastone=false; bool atleastoneglobal=false; post_order_iterator cit=st; post_order_iterator wit; exptree::fixed_depth_iterator fdi; // used when iterating at fixed depth int worked=0; int failed=0; long total_number_of_nodes=0; long processed_number_of_nodes=0; do { // loop which keeps iterating until the expression no longer changes post_order_iterator end; if(act_at_level!=-1) { fdi=tr.begin_fixed(st, act_at_level); wit=fdi; end=tr.end(); } else { total_number_of_nodes=tr.size(cit); wit=cit; end=wit; wit.descend_all(); ++end; } atleastone=false; int num=1; int applied=0; // debugout << "entering loop... for " << typeid(*this).name() << std::endl; // exptree::print_recursive_treeform(debugout, tr.begin()); while(tr.is_valid(wit) && wit!=end) { // loop over the entire tree bool change_st=false; iterator start=wit; // If we are at the top node and the algorithm changes the iterator 'start', // we have to propagate that change into 'st'. if(start==st) change_st=true; if(can_apply(start)) { // debugout << "can apply, entry point:" << std::endl; // exptree::print_recursive_treeform(debugout, start); if(global_successname).substr(1, (*this_command->name).size()-2), total_number_of_nodes, processed_number_of_nodes, 1); ++nextone; // txtout << "applying at " << *wit->name << " next is " << *nextone->name << std::endl; } else { ++fdi; if(tr.is_valid(fdi)) nextone=fdi; else nextone=end; // txtout << "applying at " << *wit->name << " next is " << *nextone->name << std::endl; } count++; ++number_of_calls; std::string www=*wit->name; // txtout << "applying at " << *start->name << std::endl; result_t res=apply(start); // debugout << "after apply: " << *(start->multiplier) << std::endl; // exptree::print_recursive_treeform(debugout, start); // exptree::print_recursive_treeform(txtout, tr.begin()); wit=start; // this copying back and forth is needed because wit has different type switch(res) { case l_no_action: ++failed; wit=nextone; break; case l_applied: global_success=g_applied; ++applied; if(change_st) st=start; if(expression_modified) { ++worked; ++number_of_modifications; atleastone=true; atleastoneglobal=true; } // Handle zeroes and ones. // debugout << "handling zeroes and ones." << std::endl; // debugout << "start tree:" << std::endl; // debugout << *start->multiplier << std::endl; // exptree::print_recursive_treeform(debugout, start); if(wit!=tr.end() && *wit->multiplier==0) { propagate_zeroes(wit,st); if(*wit->multiplier==0) { // a top-level zero ++wit; } else if(act_at_level!=-1) wit=nextone; // do not follow post_order sequence } else if(wit!=tr.end() && wit->is_rational()) { // handle multipliers in products and identity powers bool tryprod=false; bool ispow=true; sibling_iterator tmpact=wit; if( *tr.parent(tmpact)->name=="\\pow" && wit->is_identity() ) { iterator par=tr.parent(tmpact); if( tmpact==tr.begin(par) ) { // 1**x = 1 node_one(par); tmpact=par; tryprod=true; } else { // x**1 = x tr.erase(tmpact); tr.flatten(par); tr.erase(par); wit=nextone; } } else ispow=false; if( (!ispow || tryprod) && *tr.parent(tmpact)->name=="\\prod") { iterator tmp=tr.parent(tmpact); multiply(tmp->multiplier, *tmpact->multiplier); tr.erase(tmpact); // may leave us with 0 or 1 children cleanup_anomalous_products(tr,tmp); if(tryprod) wit=tmp; else wit=nextone; } else { if(tryprod) wit=tmpact; else wit=nextone; } } else { if(wit!=tr.end()) { // txtout << "THEN HERE" << std::endl; pushup_multiplier(wit); // Ensure a valid tree wrt. multipliers. // txtout << "THEN HERE DONE" << std::endl; } wit=nextone; } break; case l_error: global_success=g_apply_failed; return atleastoneglobal; break; } } else { if(act_at_level==-1) ++wit; else { ++fdi; if(tr.is_valid(fdi)) wit=fdi; else wit=end; // wit=tr.next_at_same_depth(wit); } } if(interrupted) throw algorithm_interrupted("apply_recursive"); ++num; } } while(until_nochange && atleastone); // enable this again at some point for repeatall type apply // Completely top-level zeroes did not get handled above. if(*st->name == "\\expression" && tr.begin(st)->is_zero()) { tr.erase_children(tr.begin(st)); tr.begin(st)->name=name_set.insert("1").first; } // tr.print_recursive_treeform(txtout, tr.begin()); // Check consistency of the tree if requested. if(getenv("CDB_PARANOID")) if(global_success==g_applied && check_cons) check_consistency(tr.named_parent(cit,"\\expression")); // txtout << "algorithm " << (this_command==tr.end()?"?":*this_command->name) << " worked " << worked // << " failed " << failed << std::endl; // tr.debug_verify_consistency(); // exptree::print_recursive_treeform(txtout, tr.begin()); return atleastoneglobal; } bool algorithm::prepare_for_modification(bool make_copy) { // Collect iterators pointing to all selected nodes and copy the // expression into a new \\expression node where the modifications // can be made. marks.clear(); // tr.marked_nodes(marks); if(marks.size()==0) return false; // previous_expression=tr.named_parent(marks[0], "\\expression"); if(make_copy) copy_expression(previous_expression); // for(unsigned int i=0; imultiplier==0); if(it==topnode) return; iterator walk=tr.parent(it); // debugout << *walk->name << std::endl; if(!tr.is_valid(walk)) return; const Derivative *der=properties::get(walk); if(*walk->name=="\\prod" || der) { if(der && it->is_index()) return; walk->multiplier=rat_set.insert(0).first; it=walk; propagate_zeroes(it, topnode); } else if(*walk->name=="\\pow") { if(tr.index(it)==0) { // the argument walk->multiplier=rat_set.insert(0).first; it=walk; propagate_zeroes(it, topnode); } else { // the exponent rset_t::iterator rem=walk->multiplier; tr.erase(it); tr.flatten(walk); it=tr.erase(walk); node_one(it); it->multiplier=rem; } } else if(*walk->name=="\\sum") { if(tr.number_of_children(walk)>2) { if(tr.is_valid(tr.next_sibling(it))) { it=tr.erase(it); it.descend_all(); } else { iterator ret=tr.parent(it); tr.erase(it); it=ret; } } else { // If the sum is the top node, we cannot flatten it because // we are not allowed to invalidate the topnode iterator if(walk==topnode) return; tr.erase(it); iterator singlearg=tr.begin(walk); if(singlearg!=tr.end(walk)) { singlearg->fl.bracket=walk->fl.bracket; // to remove brackets of the sum if(*tr.parent(walk)->name=="\\prod") { multiply(tr.parent(walk)->multiplier, *singlearg->multiplier); ::one(singlearg->multiplier); } } tr.flatten(walk); it=tr.erase(walk); if(*it->name=="\\prod" && *tr.parent(it)->name=="\\prod") { tr.flatten(it); it=tr.erase(it); } } } else { iterator nn=tr.insert_after(it, str_node("1")); nn->fl.parent_rel=it->fl.parent_rel; nn->fl.bracket=it->fl.bracket; it=tr.erase(it); zero(it->multiplier); } return; } void algorithm::pushup_multiplier(iterator it) { if(!tr.is_valid(it)) return; if(*it->multiplier!=1) { if(*it->name=="\\sum") { // txtout << "SUM" << std::endl; sibling_iterator sib=tr.begin(it); multiplier_t sum_multiplier=*it->multiplier; ::one(it->multiplier); while(sib!=tr.end(it)) { multiply(sib->multiplier, sum_multiplier); // txtout << "going up" << std::endl; pushup_multiplier(tr.parent(it)); // txtout << "back and back up" << std::endl; // pushup_multiplier(sib); // txtout << "back" << std::endl; ++sib; } } else { // txtout << "PUSHUP: " << *it->name << std::endl; if(tr.is_valid(tr.parent(it))) { // txtout << "test propinherit" << std::endl; // iterator tmp=tr.parent(it); // tmp not always valid?!? This one crashes hard with a loop!?! // txtout << " of " << *tmp->name << std::endl; const PropertyInherit *pin=properties::get(tr.parent(it)); if(pin || *(tr.parent(it)->name)=="\\prod") { multiply(tr.parent(it)->multiplier, *it->multiplier); // txtout << "going up" << std::endl; pushup_multiplier(tr.parent(it)); // txtout << "back" << std::endl; ::one(it->multiplier); } // else txtout << "not relevant" << std::endl; } } } } void algorithm::node_zero(iterator it) { ::zero(it->multiplier); tr.erase_children(it); it->name=name_set.insert("1").first; } void algorithm::node_one(iterator it) { ::one(it->multiplier); tr.erase_children(it); it->name=name_set.insert("1").first; } void algorithm::node_integer(iterator it, int num) { ::one(it->multiplier); tr.erase_children(it); it->name=name_set.insert("1").first; ::multiply(it->multiplier, num); } int algorithm::index_parity(iterator it) const { sibling_iterator frst=tr.begin(tr.parent(it)); sibling_iterator fnd(it); int sgn=1; while(frst!=fnd) { sgn=-sgn; ++frst; } return sgn; } bool algorithm::less_without_numbers(nset_t::iterator it1, nset_t::iterator it2) { std::string::const_iterator ch1=(*it1).begin(); std::string::const_iterator ch2=(*it2).begin(); while(ch1!=(*it1).end() && ch2!=(*it2).end()) { if(isdigit(*ch1)) return true; // bla1 < blaq if(isdigit(*ch2)) return false; // blaa !< bla1 if(*ch1>=*ch2) return false; ++ch1; ++ch2; } if(ch1==(*it1).end()) { if(ch2==(*it2).end()) return false; else return true; } return false; } bool algorithm::equal_without_numbers(nset_t::iterator it1, nset_t::iterator it2) { std::string::const_iterator ch1=(*it1).begin(); std::string::const_iterator ch2=(*it2).begin(); while(ch1!=(*it1).end() && ch2!=(*it2).end()) { if(isdigit(*ch1)) { if(isdigit(*ch2)) return true; else return false; } if(*ch1!=*ch2) return false; ++ch1; ++ch2; } if(ch1==(*it1).end()) { if(ch2==(*it2).end()) return true; else return false; } return false; } bool algorithm::check_index_consistency(iterator it) const { index_map_t ind_free, ind_dummy; classify_indices(it,ind_free,ind_dummy); return true; } bool algorithm::check_consistency(iterator it) const { stopwatch w1; w1.start(); debugout << "checking consistency ... " << std::flush; assert(*it->name=="\\expression"); // iterator entry=it; iterator end=it; end.skip_children(); ++end; while(it!=end) { if(interrupted) throw algorithm_interrupted("check_consistency"); if(*it->name=="\\sum") { if(*it->multiplier!=1) throw consistency_error("Found \\sum node with non-unit multiplier."); else if(exptree::number_of_children(it)<2) throw consistency_error("Found a \\sum node with 0 or 1 child nodes."); else { sibling_iterator sumch=it.begin(); str_node::bracket_t firstbracket=sumch->fl.bracket; while(*sumch->name=="\\sum" || *sumch->name=="\\prod") { ++sumch; if(sumch==it.end()) break; else firstbracket=sumch->fl.bracket; } sumch=it.begin(); while(sumch!=it.end()) { if(*sumch->name!="\\sum" && *sumch->name!="\\prod") { if(sumch->fl.bracket!=firstbracket) throw consistency_error("Found a \\sum node with different brackets on its children."); } // else if(*sumch->name=="\\sum") { // sibling_iterator sumchch=sumch.begin(); // while(sumchch!=sumch.end()) { // if(sumchch->fl.bracket==str_node::b_none) { // tr.print_recursive_treeform(debugout, entry); // throw consistency_error("Found a sum node with \\sum child without bracketed children."); // } // ++sumchch; // } // } ++sumch; } } } else if(*it->name=="\\prod") { if(exptree::number_of_children(it)<=1) throw consistency_error("Found \\prod node with only 0 or 1 children."); sibling_iterator ch=it.begin(); str_node::bracket_t firstbracket=ch->fl.bracket; while(*ch->name=="\\sum" || *ch->name=="\\prod") { ++ch; if(ch==it.end()) break; else firstbracket=ch->fl.bracket; } ch=it.begin(); while(ch!=it.end()) { if(*ch->name!="\\prod" && *ch->name!="\\sum") { if(ch->fl.bracket!=firstbracket) throw consistency_error("Found \\prod node with different brackets on its children."); } if(*ch->multiplier!=1) { throw consistency_error("Found \\prod child with non-unit multiplier."); // debugout << "node name " << *ch->name << ", multiplier " << *ch->multiplier << std::endl; // inconsistent=true; // break; } ++ch; } } else if(*it->name=="\\sequence") { if(exptree::number_of_children(it)!=2) throw consistency_error("Found \\sequence node with incorrect (non-2) number of children."); } ++it; } w1.stop(); debugout << "checking done..." << w1 << std::endl; return true; } void algorithm::report_progress(const std::string& str, int todo, int done, int count) { bool display=false; if(count==2) display=true; else { if(report_progress_stopwatch.stopped()) { display=true; report_progress_stopwatch.start(); } else { if(report_progress_stopwatch.seconds()>0 || report_progress_stopwatch.useconds()>300000L) { display=true; report_progress_stopwatch.reset(); } } } if(display) { // prevents updates at a rate of more than one per second if(eo->output_format==exptree_output::out_xcadabra) { txtout << "" << std::endl << str << std::endl << todo << std::endl << done << std::endl << count << std::endl << "" << std::endl; } else { if(count==2) txtout << str << " (" << done << " of " << todo << " completed)" << std::endl; } } } bool algorithm::rename_replacement_dummies(iterator two, bool still_inside_algo) { // txtout << "full story " << *two->name << std::endl; // print_classify_indices(tr.named_parent(one, "\\expression")); // txtout << "replacement" << std::endl; // print_classify_indices(two); index_map_t ind_free, ind_dummy; index_map_t ind_free_full, ind_dummy_full; if(still_inside_algo) { classify_indices_up(tr.parent(two), ind_free_full, ind_dummy_full); // print_classify_indices(tr.parent(two)); } else { // txtout << "classify indices up" << *(tr.parent(two)->name) << std::endl; classify_indices_up(two, ind_free_full, ind_dummy_full); // the indices in everything except the replacement } classify_indices(two, ind_free, ind_dummy); // the indices in the replacement subtree index_map_t must_be_empty; index_map_t newly_generated; // Catch double index pairs determine_intersection(ind_dummy_full, ind_dummy, must_be_empty); index_map_t::iterator it=must_be_empty.begin(); while(it!=must_be_empty.end()) { // txtout << "double index pair " << *((*it).first.begin()->name) // << " (index appears " << must_be_empty.count((*it).first) // << " times); renaming..." << std::endl; exptree the_key=(*it).first; const Indices *dums=properties::get(it->second, true); if(!dums) throw consistency_error("Failed to find dummy property for $"+*it->second->name+"$ while renaming dummies."); // txtout << "failed to find dummy property for " << *it->second->name << std::endl; assert(dums); exptree relabel =get_dummy(dums, &ind_dummy_full, &ind_dummy, &ind_free_full, &ind_free, &newly_generated); newly_generated.insert(index_map_t::value_type(exptree(relabel),(*it).second)); // txtout << " renamed to " << *relabel << std::endl; do { tr.replace_index((*it).second, relabel.begin()); // (*it).second->name=relabel; ++it; } while(it!=must_be_empty.end() && tree_exact_equal((*it).first,the_key, 1, true, -2, true)); } // Catch triple indices (two cases: dummy pair in replacement, free index elsewhere and // dummy elsewhere, free index in replacement) must_be_empty.clear(); // newly_generated.clear(); // DO NOT ERASE, IDIOT! determine_intersection(ind_free_full, ind_dummy, must_be_empty); it=must_be_empty.begin(); while(it!=must_be_empty.end()) { // txtout << "triple index " << *((*it).first) // << " (index appears " << must_be_empty.count((*it).first) // << " times); renaming..." << std::endl; exptree the_key=(*it).first; const Indices *dums=properties::get(it->second, true); if(!dums) throw consistency_error("Failed to find dummy property for $"+*it->second->name+"$ while renaming dummies."); assert(dums); exptree relabel =get_dummy(dums, &ind_dummy_full, &ind_dummy, &ind_free_full, &ind_free, &newly_generated); newly_generated.insert(index_map_t::value_type(relabel,(*it).second)); do { tr.replace_index((*it).second, relabel.begin()); // (*it).second->name=relabel; ++it; } while(it!=must_be_empty.end() && tree_exact_equal((*it).first,the_key, 1, true, -2, true)); } must_be_empty.clear(); // newly_generated.clear(); determine_intersection(ind_free, ind_dummy_full, must_be_empty); it=must_be_empty.begin(); while(it!=must_be_empty.end()) { // txtout << "triple index " << *((*it).first) // << " (index appears " << must_be_empty.count((*it).first) // << " times); renaming..." << std::endl; exptree the_key=(*it).first; const Indices *dums=properties::get(it->second, true); if(!dums) throw consistency_error("Failed to find dummy property for $"+*it->second->name+"$ while renaming dummies."); assert(dums); exptree relabel =get_dummy(dums, &ind_dummy_full, &ind_dummy, &ind_free_full, &ind_free, &newly_generated); newly_generated.insert(index_map_t::value_type(relabel,(*it).second)); do { tr.replace_index((*it).second, relabel.begin()); ++it; } while(it!=must_be_empty.end() && tree_exact_equal((*it).first,the_key, 1, true, -2, true)); } return true; } int algorithm::max_numbered_name_one(const std::string& nm, const index_map_t * one) const { assert(one); int themax=0; index_map_t::const_iterator it=one->begin(); while(it!=one->end()) { size_t pos=(*it->first.begin()->name).find_first_of("0123456789"); if(pos!=std::string::npos) { // txtout << (*it->first).substr(0,pos) << std::endl; if((*it->first.begin()->name).substr(0,pos) == nm) { int thenum=atoi((*it->first.begin()->name).substr(pos).c_str()); // txtout << "num = " << thenum << std::endl; themax=std::max(themax, thenum); } } ++it; } return themax; } int algorithm::max_numbered_name(const std::string& nm, const index_map_t * one, const index_map_t * two, const index_map_t * three, const index_map_t * four, const index_map_t * five) const { int themax=0; if(one) { themax=std::max(themax, max_numbered_name_one(nm, one)); if(two) { themax=std::max(themax, max_numbered_name_one(nm, two)); if(three) { themax=std::max(themax, max_numbered_name_one(nm, three)); if(four) { themax=std::max(themax, max_numbered_name_one(nm, four)); if(five) { themax=std::max(themax, max_numbered_name_one(nm, five)); } } } } } return themax; } exptree algorithm::get_dummy(const list_property *dums, const index_map_t * one, const index_map_t * two, const index_map_t * three, const index_map_t * four, const index_map_t * five) const { std::pair pr=properties::pats.equal_range(dums); while(pr.first!=pr.second) { // txtout << "trying " << std::endl; // tr.print_recursive_treeform(txtout, (*pr.first).second->obj.begin()); if(pr.first->second->obj.begin()->is_autodeclare_wildcard()) { std::string base=*pr.first->second->obj.begin()->name_only(); int used=max_numbered_name(base, one, two, three, four, five); std::ostringstream str; str << base << used+1; // txtout << "going to use " << str.str() << std::endl; nset_t::iterator newnm=name_set.insert(str.str()).first; exptree ret; ret.set_head(str_node(newnm)); return ret; } else { const exptree& inm=(*pr.first).second->obj; if(!one || one->count(inm)==0) if(!two || two->count(inm)==0) if(!three || three->count(inm)==0) if(!four || four->count(inm)==0) if(!five || five->count(inm)==0) { return inm; } } ++pr.first; } const Indices *dd=dynamic_cast(dums); assert(dd); throw consistency_error("Ran out of dummy indices for type \""+dd->set_name+"\"."); } exptree algorithm::get_dummy(const list_property *dums, iterator it) const { index_map_t one, two, three, four, five; classify_indices_up(it, one, two); classify_indices(it, three, four); return get_dummy(dums, &one, &two, &three, &four, 0); } // Find a dummy index of the type given in "nm", making sure that this index // name does not class with the object in it1 nor it2. exptree algorithm::get_dummy(const list_property *dums, iterator it1, iterator it2) const { index_map_t one, two, three, four, five; classify_indices_up(it1, one, two); classify_indices_up(it2, one, two); classify_indices(it1, three, four); classify_indices(it2, three, four); return get_dummy(dums, &one, &two, &three, &four, 0); } void algorithm::print_classify_indices(iterator st) const { index_map_t ind_free, ind_dummy; classify_indices(st, ind_free, ind_dummy); index_map_t::iterator it=ind_free.begin(); index_map_t::iterator prev=ind_free.end(); txtout << "free indices: " << std::endl; while(it!=ind_free.end()) { if(prev==ind_free.end() || tree_exact_equal((*it).first,(*prev).first,1,true,-2,true)==false) txtout << *(*it).first.begin()->name << " (" << ind_free.count((*it).first) << ") "; prev=it; ++it; } txtout << std::endl; it=ind_dummy.begin(); prev=ind_dummy.end(); txtout << "dummy indices: "; while(it!=ind_dummy.end()) { if(prev==ind_dummy.end() || tree_exact_equal((*it).first,(*prev).first,1,true,-2,true)==false) txtout << *(*it).first.begin()->name << " (" << ind_dummy.count((*it).first) << ") "; prev=it; ++it; } txtout << std::endl; } // For each iterator in the original map, find the sequential position of the index. // That is, the index 'd' has position '3' in A_{a b} C_{c} D_{d}. // WARNING: expensive operation. // void algorithm::fill_index_position_map(iterator prodnode, const index_map_t& im, index_position_map_t& ipm) const { ipm.clear(); index_map_t::const_iterator imit=im.begin(); while(imit!=im.end()) { int current_pos=0; bool found=false; exptree::index_iterator indexit=tr.begin_index(prodnode); while(indexit!=tr.end_index(prodnode)) { if(imit->second==(iterator)(indexit)) { ipm.insert(index_position_map_t::value_type(imit->second, current_pos)); found=true; break; } ++current_pos; ++indexit; } if(!found) throw consistency_error("Internal error in fill_index_position_map; cannot find index " + *(imit->first.begin()->name)+"."); ++imit; } } void algorithm::fill_map(index_map_t& mp, sibling_iterator st, sibling_iterator nd) const { while(st!=nd) { mp.insert(index_map_t::value_type(exptree(st), iterator(st))); ++st; } } // Determine those indices in 'two' which have a name which is identical to // an index name occurring in 'one'. Store these indices of 'two' in target. // If 'move_out' is true, instead move both the indices in 'one' and 'two' // (i.e. move instead of copy, and also store the 'one' index). // // One exception: numerical, coordinate and symbol indices are always kept in 'one'. // void algorithm::determine_intersection(index_map_t& one, index_map_t& two, index_map_t& target, bool move_out) const { index_map_t::iterator it1=one.begin(); while(it1!=one.end()) { const Coordinate *cdn=properties::get(it1->second, true); const Symbol *smb=Symbol::get(it1->second, true); if(it1->second->is_integer()==false && !cdn && !smb) { bool move_this_one=false; index_map_t::iterator it2=two.begin(); while(it2!=two.end()) { if(tree_exact_equal((*it1).first,(*it2).first,1,true,-2,true)) { target.insert((*it2)); if(move_out) { index_map_t::iterator nxt=it2; ++nxt; two.erase(it2); it2=nxt; move_this_one=true; } else ++it2; } else ++it2; } exptree the_key=(*it1).first; if(move_this_one && move_out) { index_map_t::iterator nxt=it1; ++nxt; target.insert(*it1); one.erase(it1); it1=nxt; } else ++it1; // skip all indices in two with the same name while(it1!=one.end() && tree_exact_equal((*it1).first,the_key,1,true,-2,true)) { if(move_this_one && move_out) { index_map_t::iterator nxt=it1; ++nxt; target.insert(*it1); one.erase(it1); it1=nxt; } else ++it1; } } else ++it1; } } // Directly add an index to the free/dummy sets, as appropriate (only add if this really is an // index!) void algorithm::classify_add_index(iterator it, index_map_t& ind_free, index_map_t& ind_dummy) const { if((it->fl.parent_rel==str_node::p_sub || it->fl.parent_rel==str_node::p_super) && it->fl.bracket==str_node::b_none /* && it->is_integer()==false */) { const Coordinate *cdn=properties::get(it, true); const Symbol *smb=Symbol::get(it, true); if(it->is_integer() || cdn || smb) ind_free.insert(index_map_t::value_type(exptree(it), it)); else { index_map_t::iterator fnd=ind_free.find(it); if(fnd!=ind_free.end()) { if(ind_dummy.count(it)>0) { txtout << "triple index occurred." << std::endl; } ind_dummy.insert(*fnd); ind_dummy.insert(index_map_t::value_type(exptree(it), it)); ind_free.erase(fnd); } else { ind_free.insert(index_map_t::value_type(exptree(it), it)); } } } } // This classifies indices bottom-up, that is, given a node, it goes up the tree to find // all free and dummy indices in the product in which this node would end up if a full // distribute would be done on the entire expression. void algorithm::classify_indices_up(iterator it, index_map_t& ind_free, index_map_t& ind_dummy) const { loopie: iterator par=exptree::parent(it); if(tr.is_valid(par)==false || par==tr.end() || *par->name=="\\expression" || *par->name=="\\history") { // reached the top return; } const IndexInherit *inh=properties::get(par); // txtout << "class: " << *par->name << std::endl; if(*par->name=="\\sum" || *par->name=="\\equals") { // sums or equal signs are no problem since the other terms do not end up in our // factor; therefore, just go up. it=par; goto loopie; } else if(*par->name=="\\fermibilinear" || inh) { // For each _other_ child in this product, do a top-down classify for all non-sub/super // children; add the indices thus found to the maps since they will end up in our factor. sibling_iterator sit=par.begin(); while(sit!=par.end()) { if(sit!=sibling_iterator(it)) { if(sit->is_index()==false) { index_map_t factor_free, factor_dummy; classify_indices(sit, factor_free, factor_dummy); // Test for absence of triple or quadruple indices index_map_t must_be_empty; determine_intersection(factor_free, ind_dummy, must_be_empty); if(must_be_empty.size()>0) txtout << "triple index occurred." << std::endl; // Test for absence of double index pairs must_be_empty.clear(); determine_intersection(factor_dummy, ind_dummy, must_be_empty); if(must_be_empty.size()>0) txtout << "double index pair occurred." << std::endl; ind_dummy.insert(factor_dummy.begin(), factor_dummy.end()); index_map_t new_dummy; determine_intersection(factor_free, ind_free, new_dummy, true); ind_free.insert(factor_free.begin(), factor_free.end()); ind_dummy.insert(new_dummy.begin(), new_dummy.end()); } else { // ind_free.insert(free_so_far.begin(), free_so_far.end()); // free_so_far.clear(); classify_add_index(sit, ind_free, ind_dummy); } } ++sit; } it=par; goto loopie; } else if(*par->name=="\\expression") { // reached the top index_sw.stop(); return; } else if((*par->name).size()>0 && (*par->name)[0]=='@') { // command nodes swallow everything index_sw.stop(); return; } else if(*par->name=="\\tie") { // tie lists do not care about indices ind_free.clear(); ind_dummy.clear(); it=par; goto loopie; } else if(*par->name=="\\arrow") { // rules can have different indices on lhs and rhs // ind_free.clear(); // ind_dummy.clear(); it=par; goto loopie; } // else if(*par->name=="\\indexbracket") { // it's really just a bracket, so go up // sibling_iterator sit=tr.begin(par); // ++sit; // while(sit!=tr.end(par)) { // ++sit; // } // it=par; // goto loopie; // } else if(*par->name=="\\comma") { // comma lists can contain anything NO: [a_{mu}, b_{nu}] // reaching a comma node is like reaching the top of an expression. return; } // FIXME: do something with these warnings!! // txtout << "Index classification for this expression failed because of " // << *par->name << " node, disabling index checking." << std::endl; // assert(1==0); ind_free.clear(); ind_dummy.clear(); } void algorithm::dumpmap(std::ostream& str, const index_map_t& mp) const { index_map_t::const_iterator dpr=mp.begin(); while(dpr!=mp.end()) { str << *(dpr->first.begin()->name) << " "; ++dpr; } str << std::endl; } // This classifies indices top-down, that is, finds the free indices and all dummy // index pairs used in the full subtree below a given node. void algorithm::classify_indices(iterator it, index_map_t& ind_free, index_map_t& ind_dummy) const { index_sw.start(); // debugout << " " << *it->name << std::endl; const IndexInherit *inh=properties::get(it); if(*it->name=="\\sum" || *it->name=="\\equals") { index_map_t first_free; sibling_iterator sit=it.begin(); bool is_first_term=true; while(sit!=it.end()) { if(*sit->multiplier!=0) { // zeroes are always ok index_map_t term_free, term_dummy; classify_indices(sit, term_free, term_dummy); if(!is_first_term) { index_map_t::iterator fri=first_free.begin(); while(fri!=first_free.end()) { const Coordinate *cdn=properties::get_composite(fri->second, true); const Symbol *smb=Symbol::get(fri->second, true); // integer, coordinate or symbol indices always ok if(fri->second->is_integer()==false && !cdn && !smb) { if(term_free.count((*fri).first)==0) { debugout << "check 1" << std::endl; debugout << "free indices elsewhere: "; dumpmap(debugout, first_free); debugout << "free indices here : "; dumpmap(debugout, term_free); if(*it->name=="\\sum") throw consistency_error("Free indices in different terms in a sum do not match."); else throw consistency_error("Free indices on lhs and rhs do not match."); } } ++fri; } fri=term_free.begin(); while(fri!=term_free.end()) { const Coordinate *cdn=properties::get_composite(fri->second, true); const Symbol *smb=Symbol::get(fri->second, true); // integer, coordinate or symbol indices always ok if(fri->second->is_integer()==false && !cdn && !smb) { if(first_free.count((*fri).first)==0) { debugout << "check 2" << std::endl; debugout << "free indices elsewhere: "; dumpmap(debugout, first_free); debugout << "free indices here : "; dumpmap(debugout, term_free); if(*it->name=="\\sum") throw consistency_error("Free indices in different terms in a sum do not match."); else throw consistency_error("Free indices on lhs and rhs do not match."); } } ++fri; } } else { first_free=term_free; is_first_term=false; } ind_dummy.insert(term_dummy.begin(), term_dummy.end()); ind_free.insert(term_free.begin(), term_free.end()); } ++sit; } } else if(inh) { index_map_t free_so_far; sibling_iterator sit=it.begin(); while(sit!=it.end()) { if(sit->is_index()==false) { index_map_t factor_free, factor_dummy; classify_indices(sit, factor_free, factor_dummy); // Test for absence of triple or quadruple indices index_map_t must_be_empty; determine_intersection(factor_free, ind_dummy, must_be_empty); if(must_be_empty.size()>0) throw consistency_error("Triple index " + *(must_be_empty.begin()->second->name) + " inside a single factor found."); // Test for absence of double index pairs must_be_empty.clear(); determine_intersection(factor_dummy, ind_dummy, must_be_empty); if(must_be_empty.size()>0) throw consistency_error("Double index pair " + *(must_be_empty.begin()->second->name) + " inside a single factor found."); ind_dummy.insert(factor_dummy.begin(), factor_dummy.end()); index_map_t new_dummy; determine_intersection(factor_free, free_so_far, new_dummy, true); free_so_far.insert(factor_free.begin(), factor_free.end()); // txtout << "free_so_far: " << free_so_far.size() << std::endl; ind_dummy.insert(new_dummy.begin(), new_dummy.end()); } else { // ind_free.insert(free_so_far.begin(), free_so_far.end()); // free_so_far.clear(); classify_add_index(sit, free_so_far, ind_dummy); } ++sit; // const Derivative *der=properties::get(it); // if(*it->name=="\\indexbracket" || der) { // the other children are indices themselves // ind_free.insert(free_so_far.begin(), free_so_far.end()); // free_so_far.clear(); // while(sit!=it.end()) { // classify_add_index(sit, ind_free, ind_dummy); // ++sit; // } // break; // } } ind_free.insert(free_so_far.begin(), free_so_far.end()); } else if(*it->name=="\\expression") { classify_indices(it.begin(), ind_free, ind_dummy); } else if(*it->name=="\\tie") { ind_free.clear(); ind_dummy.clear(); } else if((*it->name).size()>0 && (*it->name)[0]=='@') { // This is an active node that has not been replaced yet; since // we do not know anything about what this will become, do not return // any index information (clashes will be resolved when the active // node gets replaced). } else { // txtout << "classifying " << *it->name << std::endl; sibling_iterator sit=it.begin(); index_map_t item_free; index_map_t item_dummy; while(sit!=it.end()) { // txtout << *sit->name << std::endl; if((sit->fl.parent_rel==str_node::p_sub || sit->fl.parent_rel==str_node::p_super) && sit->fl.bracket==str_node::b_none /* && sit->is_integer()==false */) { if(*sit->name!="??") { const Coordinate *cdn=properties::get(sit, true); const Symbol *smb=Symbol::get(sit, true); // integer, coordinate or symbol indices always ok if(sit->is_integer() || cdn || smb) { item_free.insert(index_map_t::value_type(exptree(sit), iterator(sit))); } else { index_map_t::iterator fnd=item_free.find(exptree(sit)); if(fnd!=item_free.end()) { if(item_dummy.find(exptree(sit))!=item_dummy.end()) throw consistency_error("Triple index " + *sit->name + " inside a single factor found."); item_dummy.insert(*fnd); item_free.erase(fnd); item_dummy.insert(index_map_t::value_type(exptree(sit), iterator(sit))); } else { item_free.insert(index_map_t::value_type(exptree(sit), iterator(sit))); } } } } // else { // item_free.insert(index_map_t::value_type(sit->name, iterator(sit))); // } ++sit; } ind_free.insert(item_free.begin(), item_free.end()); ind_dummy.insert(item_dummy.begin(), item_dummy.end()); } // txtout << "ind_free: " << ind_free.size() << std::endl; // txtout << "ind_dummy: " << ind_dummy.size() << std::endl; index_sw.stop(); } bool algorithm::contains(sibling_iterator from, sibling_iterator to, sibling_iterator arg) { while(from!=to) { if(from->name==arg->name) return true; ++from; } return false; } algorithm::range_vector_t::iterator algorithm::find_arg_superset(range_vector_t& ran, sibling_iterator it) { sibling_iterator nxt=it; ++nxt; return find_arg_superset(ran, it, nxt); } void algorithm::find_argument_lists(range_vector_t& ran, bool only_comma_lists) const { sibling_iterator argit=args_begin(); while(argit!=args_end()) { if(*argit->name=="\\comma") { ran.push_back(range_t(tr.begin(argit), tr.end(argit))); } else if(!only_comma_lists) { sibling_iterator argnxt=argit; ++argnxt; ran.push_back(range_t(argit, argnxt)); } ++argit; } } template algorithm::range_vector_t::iterator algorithm::find_arg_superset(range_vector_t& ran, Iter st, Iter nd) { range_vector_t::iterator ranit=ran.begin(); while(ranit!=ran.end()) { sibling_iterator findthese=st; bool contained=true; while(findthese!=nd) { if(contains((*ranit).first, (*ranit).second, findthese)) { ++findthese; } else { contained=false; break; } } if(contained) return ranit; ++ranit; } return ran.end(); } bool algorithm::is_termlike(iterator it) { if(tr.is_valid(tr.parent(it))) { if(*tr.parent(it)->name=="\\sum" || *tr.parent(it)->name=="\\expression" || tr.parent(it)->is_command() ) return true; } return false; } bool algorithm::is_factorlike(iterator it) { if(tr.is_valid(tr.parent(it))) { if(*tr.parent(it)->name=="\\prod") return true; } return false; } bool algorithm::is_single_term(iterator it) { if(*it->name!="\\prod" && *it->name!="\\sum" && *it->name!="\\asymimplicit" && *it->name!="\\comma" && *it->name!="\\equals" && *it->name!="\\arrow") { if(tr.is_valid(tr.parent(it))) { if(*tr.parent(it)->name=="\\sum" || *tr.parent(it)->name=="\\expression" || tr.parent(it)->is_command()) return true; // if(*tr.parent(it)->name!="\\prod" && // it->fl.parent_rel==str_node::p_none) // object is an argument of a wrapping object, not an index // return true; } else return true; } return false; } bool algorithm::is_nonprod_factor_in_prod(iterator it) { if(*it->name!="\\prod" && *it->name!="\\sum" && *it->name!="\\asymimplicit" && *it->name!="\\comma" && *it->name!="\\equals") { if(tr.is_valid(tr.parent(it))) { if(*tr.parent(it)->name=="\\prod") return true; } // else return true; } return false; } bool algorithm::prod_wrap_single_term(iterator& it) { if(is_single_term(it)) { force_prod_wrap(it); return true; } else return false; } void algorithm::force_prod_wrap(iterator& it) { iterator prodnode=tr.insert(it, str_node("\\prod")); sibling_iterator fr=it, to=it; ++to; tr.reparent(prodnode, fr, to); prodnode->fl.bracket=it->fl.bracket; it->fl.bracket=str_node::b_none; prodnode->multiplier=it->multiplier; one(it->multiplier); it=prodnode; } bool algorithm::prod_unwrap_single_term(iterator& it) { if((*it->name)=="\\prod") { if(tr.number_of_children(it)==1) { multiply(tr.begin(it)->multiplier, *it->multiplier); tr.begin(it)->fl.bracket=it->fl.bracket; tr.begin(it)->multiplier=it->multiplier; tr.flatten(it); it=tr.erase(it); return true; } } return false; } bool algorithm::separated_by_derivative(iterator i1, iterator i2, iterator check_dependence) const { iterator lca = tr.lowest_common_ancestor(i1, i2); // Walk up the tree from the first node until the LCA, flag any derivatives // with which we do not commute. struct { bool operator()(exptree& tr, iterator walk, iterator lca, iterator check_dependence) { do { walk=exptree::parent(walk); if(walk == lca) break; const Derivative *der=properties::get(walk); if(der) { if(tr.is_valid(check_dependence) ) { const DependsBase *dep = properties::get_composite(check_dependence); if(dep) { exptree deps=dep->dependencies(check_dependence); sibling_iterator depobjs=deps.begin(deps.begin()); while(depobjs!=deps.end(deps.begin())) { if(walk->name == depobjs->name) { return true; } else { // compare all indices sibling_iterator indit=tr.begin(walk); while(indit!=tr.end(walk)) { if(indit->is_index()) { if(subtree_exact_equal(indit, depobjs)) return true; } ++indit; } } ++depobjs; } return false; // Dependence found but not relevant here. } else return false; // No dependence property found at all. } else return true; // Should not check for dependence. } } while(walk != lca); return false; } } one_run; if(one_run(tr, i1, lca, check_dependence)) return true; if(one_run(tr, i2, lca, check_dependence)) return true; return false; } void cleanup_expression(exptree& tr) { exptree::iterator it=tr.begin(); cleanup_expression(tr,it); } void cleanup_expression(exptree& tr, exptree::iterator& it) { // txtout << "cleanup called on " << *it->name << std::endl; // tr.print_recursive_treeform(txtout, it); ratrewrite rr(tr, tr.end()); rr.apply_recursive(it,false); // tr.print_recursive_treeform(txtout, it); reduce_sub rsub(tr, tr.end()); rsub.apply_recursive(it, false); // tr.print_recursive_treeform(txtout, it); reduce_div rdiv(tr, tr.end()); rdiv.apply_recursive(it, false); cleanup_sums_products(tr,it); // cleanup_nests_below(tr, tr.begin()); // cleanup_nests(tr,it); // FIXME: enabling this is pointless as 'it' points to \expression } void cleanup_sums_products(exptree& tr, exptree::iterator& it) { sumflatten sf(tr, tr.end()); sf.make_consistent_only=true; sf.apply_recursive(it, false); // txtout << "one" << std::endl; // tr.print_recursive_treeform(txtout, it); prodflatten pf(tr, tr.end()); pf.make_consistent_only=true; pf.apply_recursive(it, false); // collect_terms ct(tr, tr.end()); // This collect_terms makes A+A input become 2*A automatically // ct.apply_recursive(it,false); // which goes against the spirit of cdb; now disabled. prodcollectnum pc(tr, tr.end()); pc.apply_recursive(it,false); // ct.apply_recursive(it,false); } bool algorithm::cleanup_anomalous_products(exptree& tr, exptree::iterator& it) { if(*(it->name)=="\\prod") { if(tr.number_of_children(it)==0) { it->name=name_set.insert("1").first; return true; } else if(tr.number_of_children(it)==1) { tr.begin(it)->fl.bracket=it->fl.bracket; tr.begin(it)->multiplier=it->multiplier; tr.flatten(it); exptree::iterator tmp=tr.erase(it); // txtout << "HERRE?" << std::endl; pushup_multiplier(tmp); it=tmp; return true; } } return false; } void cleanup_nests_below(exptree&tr, exptree::iterator it, bool ignore_bracket_types) { if(!tr.is_valid(it)) return; exptree::iterator now=it; if(it==tr.end()) return; exptree::iterator stop=now; stop.skip_children(); ++stop; ++now; // We are not allowed to touch the content at 'it', only content below it. while(now!=stop) { cleanup_nests(tr, now, ignore_bracket_types); // Iterators should always be valid when we return here, so this test is not required. // if(tr.is_valid(now)==false) // break; ++now; } } void cleanup_nests(exptree&tr, exptree::iterator &it, bool ignore_bracket_types) { if(!tr.is_valid(it)) return; if(!tr.is_valid(tr.parent(it))) return; // tr.print_recursive_treeform(txtout, tr.begin()); if(*(it->name)=="\\prod") { assert(tr.parent(it)!=tr.end()); // txtout << "*** " << *tr.parent(it)->name << std::endl; if(*(tr.parent(it)->name)=="\\prod" && (ignore_bracket_types || tr.begin(it)->fl.bracket==it->fl.bracket) ) { multiplier_t fac=*(tr.parent(it)->multiplier)*(*it->multiplier); tr.parent(it)->multiplier=rat_set.insert(fac).first; tr.flatten(it); it=tr.erase(it); // it=tr.parent(tr.erase(it)); // CHECK: OK? } return; } if(*(it->name)=="\\sum") { assert(tr.parent(it)!=tr.end()); // txtout << "*** " << *tr.parent(it)->name << std::endl; // txtout << tr.begin(it)->fl.bracket << " " << it->fl.bracket << std::endl; if(*(tr.parent(it)->name)=="\\sum" && (ignore_bracket_types || tr.begin(it)->fl.bracket==it->fl.bracket) ) { // WARNING, this is a copy of code in sumflatten! // txtout << "still ok?" << std::endl; // tr.print_recursive_treeform(txtout, tr.begin()); exptree::sibling_iterator facs=tr.begin(tr.parent(it)); str_node::bracket_t btype_par=facs->fl.bracket; exptree::sibling_iterator terms=tr.begin(it); while(terms!=tr.end(it)) { multiply(terms->multiplier,*it->multiplier); terms->fl.bracket=btype_par; ++terms; } tr.flatten(it); // FIXME: this is dangerous: it=tr.parent(tr.erase(it)); // tr.print_recursive_treeform(txtout, tr.begin()); } return; } const PartialDerivative *der=properties::get(it); if(der) { // take constants outside multiply(it->multiplier, *(tr.begin()->multiplier)); one(tr.begin()->multiplier); // flatten nested diffs assert(tr.parent(it)!=tr.end()); der=properties::get(tr.parent(it)); if(der && tr.parent(it)->name==it->name && tr.number_of_indices(it)>0) { multiplier_t fac=*(tr.parent(it)->multiplier)*(*it->multiplier); tr.parent(it)->multiplier=rat_set.insert(fac).first; tr.flatten(it); it=tr.erase(it); // it=tr.parent(it); // CHECK: OK? } return; } } cadabra-1.39/src/algorithm.hh000066400000000000000000000271531234107666300161410ustar00rootroot00000000000000/* Cadabra: a field-theory motivated computer algebra system. Copyright (C) 2001-2011 Kasper Peeters 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 3 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, see . */ #ifndef algorithm_hh_ #define algorithm_hh_ #include #include "stopwatch.hh" #include "storage.hh" #include "props.hh" #include "display.hh" #include // These are initiated in main.cc #include extern std::ostream *fake_txtout; #define txtout (*fake_txtout) extern std::ostream *fake_forcedout; #define forcedout (*fake_forcedout) extern modglue::opipe texout; extern std::ofstream debugout; extern bool interrupted; extern stopwatch globaltime; /// An error class which can be thrown if there is no local way to recover /// from an error. Will be handled at the top level and will lead to /// the current expression being removed from the tree. class consistency_error : public std::logic_error { public: consistency_error(const std::string&); }; /// An error class which should be thrown by any algorithm as soon as it /// detects that the "interrupted" flag has been set by the sigint signal /// handler. class algorithm_interrupted : public std::logic_error { public: algorithm_interrupted(); algorithm_interrupted(const std::string&); }; /// Base class for objects which represent algorithms, i.e. which get /// expanded by the manipulator when they are encountered in the tree. class active_node { public: typedef exptree::iterator iterator; typedef exptree::post_order_iterator post_order_iterator; typedef exptree::sibling_iterator sibling_iterator; active_node(exptree&, iterator); virtual ~active_node() {}; // Helpers for iterating over or inspecting argument lists. sibling_iterator args_begin() const; sibling_iterator args_end() const; unsigned int number_of_args() const; bool has_argument(const std::string&) const; iterator this_command; protected: exptree& tr; mutable sibling_iterator args_begin_; mutable sibling_iterator args_end_; // Return the number of elements in the first range for which an identical element // is present in the second range. template unsigned int intersection_number(sibling_iterator, sibling_iterator, sibling_iterator, sibling_iterator, BinaryPredicate) const; }; /// \brief Base class for all algorithms, containing generic routines and in particular /// the logic for index classification. /// /// All commands in cadabra are classes which derive from the algorithm class. An object /// gets instantiated by the logic in the manipulator class, which then activates the /// algorithm. /// This base class contains various functions that are quite generic and often needed. /// In particular, all logic that deals with index classification is located here. class algorithm : public active_node { public: algorithm(exptree&, iterator); virtual ~algorithm(); class constructor_error { public: constructor_error(); }; enum result_t { l_no_action, l_applied, l_error }; enum global_success_t { g_not_yet_started=0, g_arguments_accepted=1, g_operand_determined=2, g_applied=4, g_apply_failed=6 }; virtual bool is_output_module() const; virtual bool can_apply(iterator)=0; // virtual bool can_apply(sibling_iterator, sibling_iterator); // These return their result in the return value virtual result_t apply(iterator&)=0; // virtual result_t apply(sibling_iterator&, sibling_iterator&); // These give result in global_success. bool apply_recursive(iterator&, bool check_consistency=true, int act_at_level=-1, bool called_by_manipulator=false, bool until_nochange=false); void apply(unsigned int last_used_equation_number, bool multiple, bool until_nochange, bool make_copy, int act_at_level=-1, bool called_by_manipulator=false); // Per-call information bool expression_modified; iterator subtree; // subtree to be displayed unsigned int equation_number; // External handling of scalar expressions // Global information global_success_t global_success; unsigned int number_of_calls; unsigned int number_of_modifications; bool suppress_normal_output; bool discard_command_node; // Any output should be handled using this output object. exptree_output *eo; // Given an \expression node, check consistency bool check_consistency(iterator) const; bool check_index_consistency(iterator) const; static stopwatch index_sw; static stopwatch get_dummy_sw; void report_progress(const std::string&, int todo, int done, int count=2); stopwatch report_progress_stopwatch; protected: unsigned int last_used_equation_number; // FIXME: this is a hack, just to see this in 'eqn'. std::vector > marks; iterator previous_expression; bool dont_iterate; // Index stuff int index_parity(iterator) const; static bool less_without_numbers(nset_t::iterator, nset_t::iterator); static bool equal_without_numbers(nset_t::iterator, nset_t::iterator); /// Finding objects in sets. typedef std::pair range_t; typedef std::vector range_vector_t; bool contains(sibling_iterator from, sibling_iterator to, sibling_iterator arg); void find_argument_lists(range_vector_t&, bool only_comma_lists=true) const; template range_vector_t::iterator find_arg_superset(range_vector_t&, Iter st, Iter nd); range_vector_t::iterator find_arg_superset(range_vector_t&, sibling_iterator it); /// Determine structure (version-2) bool is_termlike(iterator); bool is_factorlike(iterator); /// Take a single non-product node in a sum and wrap it in a /// product node, so it can be handled on the same footing as a proper product. bool is_single_term(iterator); bool is_nonprod_factor_in_prod(iterator); bool prod_wrap_single_term(iterator&); bool prod_unwrap_single_term(iterator&); /// Wrap a term in a product, irrespective of its parent (it usually makes /// more sense to call the safer prod_wrap_single_term above). void force_prod_wrap(iterator&); /// Figure out whether two objects (commonly indices) are separated by a derivative /// operator, as in \partial_{a}{A_{b}} C^{b}. /// If the last iterator is pointing to a valid node, check whether it is /// independent of the derivative (using the Depends property). bool separated_by_derivative(iterator, iterator, iterator check_dependence) const; // Given a node with non-zero multiplier, distribute this // multiplier up the tree when the node is a \sum node, or push it into the // \prod node if that is the parent. Do this recursively // in case a child is a sum as well. Note that 'pushup' is actually 'pushdown' // in the case of sums. // This never changes the tree structure, only the distribution of multipliers. void pushup_multiplier(iterator); // Turn a node into a '1' or '0' node. void node_zero(iterator); void node_one(iterator); void node_integer(iterator, int); /// A map from a pattern to the position where it occurs in the tree. typedef std::multimap index_map_t; /// A map from the position of each index to the sequential index. typedef std::map index_position_map_t; /// @name Index manipulation and classification /// /// Routines to find and classify all indices in an expression, taking into account /// sums and products. Note that dummy indices do not always come in pairs, for /// instance in expressions like /// a_{m n} ( b^{n p} + q^{n p} ) . /// Similarly, free indices can appear multiple times, as in /// a_{m} + b_{m} . //@{ /// One void fill_index_position_map(iterator, const index_map_t&, index_position_map_t&) const; /// Two void fill_map(index_map_t&, sibling_iterator, sibling_iterator) const; bool rename_replacement_dummies(iterator, bool still_inside_algo=false); void print_classify_indices(iterator) const; void determine_intersection(index_map_t& one, index_map_t& two, index_map_t& target, bool move_out=false) const; void classify_add_index(iterator it, index_map_t& ind_free, index_map_t& ind_dummy) const; void classify_indices_up(iterator, index_map_t& ind_free, index_map_t& ind_dummy) const; void classify_indices(iterator, index_map_t& ind_free, index_map_t& ind_dummy) const; int max_numbered_name_one(const std::string& nm, const index_map_t * one) const; int max_numbered_name(const std::string&, const index_map_t *m1, const index_map_t *m2=0, const index_map_t *m3=0, const index_map_t *m4=0, const index_map_t *m5=0) const; exptree get_dummy(const list_property *, const index_map_t *m1, const index_map_t *m2=0, const index_map_t *m3=0, const index_map_t *m4=0, const index_map_t *m5=0) const; exptree get_dummy(const list_property *, iterator) const; exptree get_dummy(const list_property *, iterator, iterator) const; //@} private: void cancel_modification(); void copy_expression(exptree::iterator) const; bool prepare_for_modification(bool make_copy); /// Given a node with zero multiplier, propagate this zero /// upwards in the tree. Changes the iterator so that it points /// to the next node in a post_order traversal (post_order: /// children first, then node). The second node is the topmost /// node, beyond which this routine is not allowed to touch the /// tree (i.e. the 2nd iterator will always remain valid). void propagate_zeroes(post_order_iterator&, const iterator&); void dumpmap(std::ostream&, const index_map_t&) const; bool cleanup_anomalous_products(exptree& tr, exptree::iterator& it); }; void cleanup_expression(exptree&); void cleanup_expression(exptree&, exptree::iterator&); // may change the pointer! void cleanup_sums_products(exptree&, exptree::iterator&); void cleanup_nests(exptree&tr, exptree::iterator &it, bool ignore_bracket_types=false); void cleanup_nests_below(exptree&tr, exptree::iterator it, bool ignore_bracket_types=false); template std::auto_ptr create(exptree& tr, exptree::iterator it) { return std::auto_ptr(new T(tr, it)); } /// Determine the number of elements in the first range which also occur in the /// second range. template unsigned int active_node::intersection_number(sibling_iterator from1, sibling_iterator to1, sibling_iterator from2, sibling_iterator to2, BinaryPredicate fun) const { unsigned int ret=0; sibling_iterator it1=from1; while(it1!=to1) { sibling_iterator it2=from2; while(it2!=to2) { if(fun(*it1,*it2)) ++ret; ++it2; } ++it1; } return ret; } #endif cadabra-1.39/src/combinatorics.cc000066400000000000000000000046641234107666300167770ustar00rootroot00000000000000/* Cadabra: a field-theory motivated computer algebra system. Copyright (C) 2001-2011 Kasper Peeters 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 3 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, see . */ #include "combinatorics.hh" unsigned long combin::factorial(unsigned int x) { unsigned long ret=1; while(x) { ret*=x--; } return ret; } int combin::determine_intersection_ranges(const combin::range_vector_t& prod, const combin::range_vector_t& indv, combin::range_vector_t& target) { int ret=1; for(unsigned int i=0; i=2) { ret*=factorial(newrange.size()); target.push_back(newrange); } } } return ret; } long combin::vector_sum(const std::vector& v) { long ret=0; for(unsigned int i=0; i& v) { unsigned long ret=1; for(unsigned int i=0; i& v) { unsigned long ret=1; for(unsigned int i=0; i& one, const std::vector& two) { if(one.size()!=two.size()) return false; for(unsigned int k=0; k& one) { long ret=1; for(unsigned int k=0; k 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 3 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, see . */ /* length vector normal combinations: one element, value=total length. normal permutations: n elements, each equal to 1. */ #ifndef combinatorics_hh_ #define combinatorics_hh_ #include #include #include #include #include #include namespace combin { typedef std::vector range_t; typedef std::vector range_vector_t; typedef std::vector weights_t; unsigned long factorial(unsigned int x); /// sum of elements long vector_sum(const std::vector&); /// product of elements unsigned long vector_prod(const std::vector&); /// product of factorials of elements unsigned long vector_prod_fact(const std::vector&); bool operator==(const std::vector&, const std::vector&); /// compute a hash value for a vector of unsigned ints long hash(const std::vector&); template class combinations_base { public: combinations_base(); combinations_base(const std::vector&); virtual ~combinations_base(); void permute(long start=-1, long end=-1); virtual void clear(); virtual void clear_results(); unsigned int sum_of_sublengths() const; void set_unit_sublengths(); unsigned int multiplier(const std::vector&) const; unsigned int total_permutations() const; // including the ones not stored enum weight_cond { weight_equals, weight_less, weight_greater }; unsigned int block_length; std::vector sublengths; range_vector_t input_asym; std::vector original; bool multiple_pick; std::vector weights; std::vector max_weights; std::vector weight_conditions; unsigned int sub_problem_blocksize; // when non-zero, do permutations within protected: virtual void vector_generated(const std::vector&)=0; virtual bool entry_accepted(unsigned int current) const; std::vector temparr; long start_, end_, vector_generated_called_; std::vector current_weight; private: bool is_allowed_by_weight_constraints(unsigned int i); bool final_weight_constraints_check() const; void update_weights(unsigned int i); void restore_weights(unsigned int i); void nextstep(unsigned int current, unsigned int fromalgehad, unsigned int groupindex, std::vector algehad); }; template class combinations : public combinations_base { public: typedef typename std::vector > permuted_sets_t; typedef typename permuted_sets_t::const_iterator const_iterator; combinations(); combinations(const std::vector&); virtual ~combinations(); virtual void clear(); virtual void clear_results(); const std::vector& operator[](unsigned int) const; int ordersign(unsigned int) const; unsigned int size() const; unsigned int multiplier(unsigned int) const; protected: virtual void vector_generated(const std::vector&); private: permuted_sets_t storage; }; template class symmetriser; template class symm_helper : public combinations_base { public: symm_helper(symmetriser&); virtual void clear(); int current_multiplicity; protected: bool first_one; symmetriser& owner_; virtual void vector_generated(const std::vector&); }; template class symm_val_helper : public combinations_base { public: symm_val_helper(symmetriser&); virtual void clear(); int current_multiplicity; protected: bool first_one; symmetriser& owner_; virtual void vector_generated(const std::vector&); }; template class symmetriser { public: symmetriser(); void apply_symmetry(long start=-1, long end=-1); std::vector original; unsigned int block_length; std::vector permute_blocks; // offset in unit elements! (not in blocks) std::vector value_permute; int permutation_sign; std::vector sublengths; // refers to position within permute_blocks range_vector_t input_asym; // as in combinations_base range_vector_t sublengths_scattered; // sublengths, in original, but not connected. /// Convert vectors of values to vectors of locations in the original /// (mainly useful to create input_asym for permutation by value). range_t values_to_locations(const std::vector& values) const; const std::vector& operator[](unsigned int) const; int signature(unsigned int) const; void set_multiplicity(unsigned int pos, int val); unsigned int size() const; void clear(); /// Collect equal entries, and adjust the multiplier field accordingly. void collect(); void remove_multiplicity_zero(); friend class symm_helper; friend class symm_val_helper; private: symm_helper sh_; symm_val_helper svh_; unsigned int current_; std::vector > originals; std::vector multiplicity; }; int determine_intersection_ranges(const range_vector_t& prod, const range_vector_t& indv, range_vector_t& target); template int ordersign(iterator1 b1, iterator1 e1, iterator2 b2, iterator2 e2, int stepsize=1); template int ordersign(iterator1 b1, iterator1 e1); template T fact(T x); template std::ostream& operator<<(std::ostream& str, const symmetriser& sym); /* I assume PI consists of the integers 1 to N. It can be done with O(N) comparisons and transpositions of integers in the list. sign:= 1; for i from 1 to N do while PI[i] <> i do interchange PI[i] and PI[PI[i]]; sign:= -sign od od */ template int ordersign(iterator1 b1, iterator1 e1, iterator2 b2, iterator2 e2, int stepsize) { int sign=1; std::vector crossedoff(std::distance(b1,e1),false); while(b1!=e1) { int otherpos=0; iterator2 it=b2; while(it!=e2) { if((*it)==(*b1) && crossedoff[otherpos]==false) { crossedoff[otherpos]=true; break; } else { if(!crossedoff[otherpos]) sign=-sign; } it+=stepsize; ++otherpos; } b1+=stepsize; } return sign; } //template //int ordersign(iterator1 b1, iterator1 e1, iterator2 b2, iterator2 e2, comparator cmp, int stepsize) // { // int sign=1; // std::vector crossedoff(std::distance(b1,e1),false); // while(b1!=e1) { // int otherpos=0; // iterator2 it=b2; // while(it!=e2) { // if(cmp((*it), (*b1)) && crossedoff[otherpos]==false) { // crossedoff[otherpos]=true; // break; // } // else { // if(!crossedoff[otherpos]) // sign=-sign; // } // it+=stepsize; // ++otherpos; // } // b1+=stepsize; // } // return sign; // } template int ordersign(iterator1 b1, iterator1 e1) { std::vector fil; for(int k=0; k T fact(T x) { T ret=1; assert(x>=0); while(x!=0) { ret*=x--; } return ret; } // Implementations template combinations_base::combinations_base() : block_length(1), multiple_pick(false), sub_problem_blocksize(0) { } template combinations_base::combinations_base(const std::vector& oa) : block_length(1), original(oa), multiple_pick(false), sub_problem_blocksize(0) { } template combinations::combinations() : combinations_base() { } template combinations::combinations(const std::vector& oa) : combinations_base(oa) { } template combinations_base::~combinations_base() { } template combinations::~combinations() { } template void combinations::vector_generated(const std::vector& toadd) { ++this->vector_generated_called_; if((this->start_==-1 || this->vector_generated_called_ >= this->start_) && (this->end_==-1 || this->vector_generated_called_ < this->end_)) { std::vector newone(toadd.size()*this->block_length); for(unsigned int i=0; iblock_length; ++bl) newone[i*this->block_length+bl]=this->original[toadd[i]*this->block_length+bl]; storage.push_back(newone); } } template bool combinations_base::entry_accepted(unsigned int) const { return true; } template void combinations_base::permute(long start, long end) { start_=start; end_=end; vector_generated_called_=-1; // Initialise weight handling. current_weight.clear(); current_weight.resize(weights.size(), 0); for(unsigned int i=0; i0) { if(weight_conditions.size()==0) weight_conditions.resize(weights.size(), weight_equals); else assert(weight_conditions.size()==weights.size()); } else assert(weight_conditions.size()==0); // Sublength handling. assert(sublengths.size()!=0); unsigned int len=sum_of_sublengths(); // Consistency checks. assert(original.size()%block_length==0); if(!multiple_pick) assert(len*block_length<=original.size()); for(unsigned int i=0; iinput_asym.size(); ++i) std::sort(this->input_asym[i].begin(), this->input_asym[i].end()); temparr=std::vector(len/* *block_length*/); std::vector algehad(original.size()/block_length,false); nextstep(0,0,0,algehad); } template void combinations_base::clear() { block_length=1; sublengths.clear(); this->input_asym.clear(); original.clear(); weights.clear(); max_weights.clear(); weight_conditions.clear(); sub_problem_blocksize=0; temparr.clear(); current_weight.clear(); } template void combinations_base::clear_results() { temparr.clear(); } template void combinations::clear() { storage.clear(); combinations_base::clear(); } template void combinations::clear_results() { storage.clear(); combinations_base::clear_results(); } template const std::vector& combinations::operator[](unsigned int i) const { assert(i unsigned int combinations::size() const { return storage.size(); } template unsigned int combinations_base::sum_of_sublengths() const { unsigned int ret=0; for(unsigned int i=0; i unsigned int combinations_base::total_permutations() const { return vector_generated_called_+1; } template void combinations_base::set_unit_sublengths() { sublengths.clear(); for(unsigned int i=0; i int combinations::ordersign(unsigned int num) const { assert(numblock_length); } template unsigned int combinations::multiplier(unsigned int num) const { return combinations_base::multiplier(this->storage[num]); } template unsigned int combinations_base::multiplier(const std::vector& stor) const { unsigned long numerator=1; for(unsigned int i=0; iinput_asym.size(); ++i) numerator*=fact(this->input_asym[i].size()); unsigned long denominator=1; for(unsigned int i=0; iinput_asym.size(); ++i) { // for each input asym, and for each output asym, count // the number of overlap elements. unsigned int current=0; for(unsigned int k=0; ksublengths.size(); ++k) { if(this->sublengths[k]>1) { unsigned int overlap=0; for(unsigned int slc=0; slcsublengths[k]; ++slc) { for(unsigned int j=0; jinput_asym[i].size(); ++j) { unsigned int index=0; while(!(stor[current]==this->original[index])) ++index; if(index==this->input_asym[i][j]) ++overlap; } ++current; } if(overlap>0) denominator*=fact(overlap); // FIXME: for each overlap thus found, divide out by a factor // due to the fact that output asym ranges can overlap. // well, that's not right either. } else ++current; } } return numerator/denominator; } template bool combinations_base::is_allowed_by_weight_constraints(unsigned int i) { if(weights.size()==0) return true; for(unsigned int cn=0; cn= max_weights[cn]) return false; } return true; } template bool combinations_base::final_weight_constraints_check() const { for(unsigned int cn=0; cn void combinations_base::update_weights(unsigned int i) { if(weights.size()==0) return; for(unsigned int cn=0; cn void combinations_base::restore_weights(unsigned int i) { if(weights.size()==0) return; for(unsigned int cn=0; cn void combinations_base::nextstep(unsigned int current, unsigned int lowest_in_group, unsigned int groupindex, std::vector algehad) { unsigned int grouplen=0; for(unsigned int i=0; i<=groupindex; ++i) grouplen+=sublengths[i]; if(current==grouplen) { // group is filled ++groupindex; if(groupindex==sublengths.size()) { if(final_weight_constraints_check()) vector_generated(temparr); return; } lowest_in_group=0; } unsigned int starti=0, endi=original.size()/block_length; if(sub_problem_blocksize>0) { starti=current-current%sub_problem_blocksize; endi=starti+sub_problem_blocksize; } for(unsigned int i=starti; iinput_asym.size(); ++k) { for(unsigned int kk=0; kkinput_asym[k].size(); ++kk) { if(i==this->input_asym[k][kk]) { unsigned int k2=kk; while(k2!=0) { --k2; if(!algehad[this->input_asym[k][k2]]) { // std::cout << "discarding " << std::endl; discard=true; break; } } } } if(discard) break; } } else discard=true; if(!discard) if(i+1>lowest_in_group) { algehad[i]=true; update_weights(i); temparr[current]=i; // for(unsigned bl=0; bl symmetriser::symmetriser() : block_length(1), permutation_sign(1), sh_(*this), svh_(*this) { } template void symmetriser::clear() { original.clear(); block_length=1; permute_blocks.clear(); value_permute.clear(); permutation_sign=1; sublengths.clear(); input_asym.clear(); sublengths_scattered.clear(); originals.clear(); multiplicity.clear(); } template void symmetriser::collect() { std::cout << "collecting" << std::endl; // Fill the hash map: entries which are equal have to sit in the same // bin, but there may be other entries in that bin which still have to // be separated. std::multimap hashmap; for(unsigned int i=0; i(hash(originals[i]), i)); // Collect equal vectors. std::multimap::iterator it=hashmap.begin(), thisbin1, thisbin2, tmpit; while(it!=hashmap.end()) { long current_hash=it->first; thisbin1=it; while(thisbin1!=hashmap.end() && thisbin1->first==current_hash) { thisbin2=thisbin1; ++thisbin2; while(thisbin2!=hashmap.end() && thisbin2->first==current_hash) { if(originals[(*thisbin1).second]==originals[(*thisbin2).second]) { multiplicity[(*thisbin1).second]+=multiplicity[(*thisbin2).second]; multiplicity[(*thisbin2).second]=0; tmpit=thisbin2; ++tmpit; hashmap.erase(thisbin2); thisbin2=tmpit; } else ++thisbin2; } ++thisbin1; } it=thisbin1; } remove_multiplicity_zero(); } template void symmetriser::remove_multiplicity_zero() { std::vector > new_originals; std::vector new_multiplicity; for(unsigned int k=0; k void symmetriser::apply_symmetry(long start, long end) { unsigned int current_length=originals.size(); if(current_length==0) { originals.push_back(original); multiplicity.push_back(1); current_length=1; } // Some options are mutually exclusive. assert(permute_blocks.size()>0 || value_permute.size()>0); assert(sublengths.size()==0 || sublengths_scattered.size()==0); if(permute_blocks.size()==0) { // permute by value assert(value_permute.size()!=0); if(input_asym.size()==0 && sublengths_scattered.size()==0) { // When permuting by value, we can do the permutation once, // and then figure out (see vector_generated of symm_val_helper), // for each permutation which is already stored in the symmetriser, // how the objects are moved. current_=current_length; svh_.clear(); svh_.original=value_permute; svh_.input_asym.clear(); svh_.sublengths=sublengths; svh_.current_multiplicity=combin::vector_prod_fact(sublengths); if(svh_.sublengths.size()==0) svh_.set_unit_sublengths(); svh_.permute(start, end); // Since we do not divide by the number of permutations, we need // to adjust the multiplicity of all the originals. // for(unsigned int i=0; i my_permute_blocks; // Determine the location of the values. for(unsigned int k=0; k0) { // Re-order my_permute_blocks in such a way that the objects which sit // in one sublength_scattered range are consecutive. This does not make // any difference for the sign. sh_.sublengths.clear(); std::vector reordered_permute_blocks; for(unsigned int m=0; m::iterator it=my_permute_blocks.begin(); while(it!=my_permute_blocks.end()) { if((*it)==sublengths_scattered[m][mm]) { // std::cout << " found " << std::endl; reordered_permute_blocks.push_back(*it); my_permute_blocks.erase(it); ++overlap; break; } ++it; } // std::cout << std::endl; } if(overlap>0) sh_.sublengths.push_back(overlap); } std::vector::iterator it=my_permute_blocks.begin(); while(it!=my_permute_blocks.end()) { reordered_permute_blocks.push_back(*it); // std::cout << "adding one" << std::endl; sh_.sublengths.push_back(1); ++it; } my_permute_blocks=reordered_permute_blocks; // std::cout << "handled sublengths" << std::endl; } // Put to-be-permuted data in originals. for(unsigned int k=0; k0) { // Make a proper input_asym which refers to object locations // in the permute blocks array, rather than in the original // array. for(unsigned int k=0; k1) { subprob_input_asym.push_back(newrange); sh_.current_multiplicity*=fact(newrange.size()); } } } if(sh_.sublengths.size()==0) sh_.set_unit_sublengths(); sh_.current_multiplicity*=combin::vector_prod_fact(sh_.sublengths); // debugging // std::cout << "my_permute_blocks: "; // for(unsigned int ii=0; ii0) { // for(unsigned int k=0; k0); // When permuting by location, we have to apply the permutation // algorithm separately to each and every permutation which is // already stored in the symmetriser. for(unsigned int i=0; i const std::vector& symmetriser::operator[](unsigned int i) const { assert(i unsigned int symmetriser::size() const { return originals.size(); } template range_t symmetriser::values_to_locations(const std::vector& values) const { range_t ret; for(unsigned int i=0; i symm_val_helper::symm_val_helper(symmetriser& tt) : current_multiplicity(1), first_one(true), owner_(tt) { } template void symm_val_helper::clear() { first_one=true; combinations_base::clear(); } template void symm_val_helper::vector_generated(const std::vector& vec) { ++this->vector_generated_called_; if(first_one) { first_one=false; } else { if((this->start_==-1 || this->vector_generated_called_ >= this->start_) && (this->end_==-1 || this->vector_generated_called_ < this->end_)) { // Since we permuted by value, we can do this permutation in one // shot on all previously generated sets. for(unsigned int i=0; ioriginal[j]) { owner_.originals[loc][k]=this->original[vec[j]]; break; } } } } } } } template symm_helper::symm_helper(symmetriser& tt) : current_multiplicity(1), first_one(true), owner_(tt) { } template void symm_helper::clear() { first_one=true; combinations_base::clear(); } template int symmetriser::signature(unsigned int i) const { assert(i void symmetriser::set_multiplicity(unsigned int i, int val) { assert(i void symm_helper::vector_generated(const std::vector& vec) { ++this->vector_generated_called_; if(first_one) { first_one=false; } else { if((this->start_==-1 || this->vector_generated_called_ >= this->start_) && (this->end_==-1 || this->vector_generated_called_ < this->end_)) { // std::cout << "produced "; // for(unsigned int m=0; m std::ostream& operator<<(std::ostream& str, const symmetriser& sym) { for(unsigned int i=0; i #define GLIBMM_VER cadabra-1.39/src/defaults.cc000066400000000000000000000026251234107666300157450ustar00rootroot00000000000000/* Cadabra: a field-theory motivated computer algebra system. Copyright (C) 2001-2011 Kasper Peeters 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 3 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, see . */ #include std::string defaults="\\prod{#}::Distributable.\n\ \\prod{#}::IndexInherit.\n\ \\prod{#}::CommutingAsProduct.\n\ \\prod{#}::DependsInherit.\n\ \\prod{#}::WeightInherit(label=all, type=Multiplicative).\n\ \\prod{#}::NumericalFlat.\n\ \n\ \\sum{#}::CommutingAsSum.\n\ \\sum{#}::DependsInherit.\n\ \\sum{#}::IndexInherit.\n\ \\sum{#}::WeightInherit(label=all, type=Additive).\n\ \n\ \\pow{#}::DependsInherit.\n\ \n\ \\indexbracket{#}::Distributable.\n\ \\indexbracket{#}::IndexInherit.\n\ \\commutator{#}::IndexInherit.\n\ \\commutator{#}::Derivative.\n\ \\anticommutator{#}::IndexInherit.\n\ \\anticommutator{#}::Derivative.\n\ "; cadabra-1.39/src/display.cc000066400000000000000000001246151234107666300156070ustar00rootroot00000000000000/* Cadabra: a field-theory motivated computer algebra system. Copyright (C) 2001-2011 Kasper Peeters 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 3 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, see . */ #include "display.hh" #include "manipulator.hh" #include "props.hh" #include "modules/algebra.hh" #include "modules/relativity.hh" #include "modules/gamma.hh" #include "modules/output.hh" #include #include #define nbsp (( parent.utf8_output?(unichar(0x00a0)):" ")) #define zwnbsp (( parent.utf8_output?(unichar(0xfeff)):"")) exptree_output::exptree_output(const exptree& tr_, output_format_t of) : tight_star(getenv("CDB_TIGHTSTAR")), tight_plus(getenv("CDB_TIGHTPLUS")), tight_brackets(getenv("CDB_TIGHTBRACKETS")), print_star(getenv("CDB_PRINTSTAR")), output_format(of), xml_structured(false), utf8_output(false), print_expression_number(true), tr(tr_), bracket_level(0), print_default_(&create) { setup_handlers(); } void exptree_output::setup_handlers(bool infix) { printers_.clear(); if(infix) { switch(output_format) { case out_mathml: printers_["\\expression"] =&create; printers_["\\prod"] =&create; printers_["\\frac"] =&create; printers_["\\sum"] =&create; printers_["\\pow"] =&create; printers_["\\indexbracket"] =&create; printers_["\\factorial"] =&create; printers_["\\equals"] =&create; printers_["\\unequals"] =&create; // printers_["\\conditional"] =&create; printers_["\\sequence"] =&create; printers_["\\comma"] =&create; // FIXME: these two are not yet declared reserved? printers_["\\wedge"] =&create; // printers_["\\commutator"] =&create; break; default: printers_["\\expression"] =&create; printers_["\\frac"] =&create; // printers_["\\wedge"] =&create; printers_["\\prod"] =&create; printers_["\\sum"] =&create; printers_["\\equals"] =&create; printers_["\\unequals"] =&create; printers_["\\conditional"] =&create; printers_["\\regex"] =&create; printers_["\\arrow"] =&create; printers_["\\cdot"] =&create; printers_["\\comma"] =&create; printers_["\\factorial"] =&create; printers_["\\sequence"] =&create; printers_["\\commutator"] =&create; printers_["\\anticommutator"]=&create; printers_["\\indexbracket"] =&create; printers_["\\pow"] =&create; printers_["\\sqrt"] =&create; if(output_format==out_xcadabra) { printers_prop_["Tableau"] = &create; printers_prop_["FilledTableau"] = &create; printers_prop_["Derivative"] = &create; printers_prop_["PartialDerivative"] = &create; } break; } } } void exptree_output::newline(std::ostream& str) { switch(output_format) { case out_xcadabra: str << "\\\\" << std::endl; break; default: str << std::endl; } } display_error::display_error() { } display_interrupted::display_interrupted() { } std::auto_ptr exptree_output::get_printer(exptree::iterator it) { if(interrupted) { interrupted=false; throw display_interrupted(); } printmap_t::const_iterator prit=printers_.find(*it->name); // Match based on node name. if(prit!=printers_.end()) return (*prit).second(*this); // Match based on property. printmap_prop_t::iterator pp=printers_prop_.begin(); while(pp!=printers_prop_.end()) { properties::registered_property_map_t::iterator pit= properties::registered_properties.store.find((*pp).first); const property_base *aprop=pit->second(); bool ret=properties::has(aprop, it); if(ret) return (*pp).second(*this); ++pp; } // Default verbatim output. return print_default_(*this); } void exptree_output::print_infix(std::ostream& str, exptree::iterator start) { setup_handlers(true); if(output_format==out_texmacs) str << DATA_BEGIN << "latex:$"; get_printer(start)->print_infix(str, start); if(output_format==out_texmacs) str << "$" << DATA_END << std::flush; } void exptree_output::print_prefix(std::ostream& str, exptree::iterator start) { setup_handlers(false); get_printer(start)->print_infix(str, start); } print_expression::print_expression(exptree_output& eo) : node_printer(eo) { } void print_expression::print_infix(std::ostream& str, exptree::iterator it) { // We print only the subtree starting at the first sibling node. // All other subtrees are supposed to contain other information, // like the externally (anti)symmetrised indices, which should // be displayed in a different way. parent.get_printer(tr.begin(it))->print_infix(str, tr.begin(it)); } /* --------------------------------------------------------------------- */ print_wedge::print_wedge(exptree_output& eo) : print_productlike(eo) { } void print_wedge::print_infix(std::ostream& str, exptree::iterator it) { doprint(str, it, "^"); } print_prod::print_prod(exptree_output& eo) : print_productlike(eo) { } void print_prod::print_infix(std::ostream& str, exptree::iterator it) { doprint(str, it, "*"); } print_productlike::print_productlike(exptree_output& eo) : node_printer(eo) { } void print_productlike::doprint(std::ostream& str, exptree::iterator it, const std::string& inbetween) { // bool close_bracket=false; if(*it->multiplier!=1) { print_multiplier(str, it); // sibling_iterator st=tr.begin(it); // while(st!=tr.end(it)) { // if(*st->name=="\\sum") { // str << "("; // close_bracket=true; // break; // } // ++st; // } } // To print \prod{\sum{a}{b}}{\sum{c}{d}} correctly: // If there is any sum as child, and if the sum children do not // all have the same bracket type (different from b_none or b_no), // then print brackets. str_node::bracket_t previous_bracket_=str_node::b_invalid; bool beginning_of_group=true; sibling_iterator ch=tr.begin(it); while(ch!=tr.end(it)) { str_node::bracket_t current_bracket_=(*ch).fl.bracket; if(previous_bracket_!=current_bracket_) { if(current_bracket_!=str_node::b_none) { print_opening_bracket(str, current_bracket_, str_node::p_none); beginning_of_group=true; } } parent.get_printer(ch)->print_infix(str, ch); ++ch; if(ch==tr.end(it)) { if(current_bracket_!=str_node::b_none) print_closing_bracket(str, current_bracket_, str_node::p_none); } if(ch!=tr.end(it)) { if(parent.print_star && parent.output_format != exptree_output::out_texmacs) { if(parent.tight_star) str << inbetween; else if(parent.utf8_output) { str << unichar(0x00a0) << inbetween << unichar(0x00a0); } else str << " " << inbetween << " "; } else { if(parent.output_format==exptree_output::out_texmacs) str << "\\,"; else str << " "; } } previous_bracket_=current_bracket_; } // if(close_bracket) str << ")"; } print_arrow::print_arrow(exptree_output& eo) : node_printer(eo) { } void print_arrow::print_infix(std::ostream& str, exptree::iterator it) { sibling_iterator lhs=tr.begin(it), rhs=lhs; ++rhs; parent.get_printer(lhs)->print_infix(str, lhs); if(parent.output_format==exptree_output::out_xcadabra || parent.output_format==exptree_output::out_texmacs ) str << " \\rightarrow "; else str << " -> "; parent.get_printer(rhs)->print_infix(str, rhs); } print_dot::print_dot(exptree_output& eo) : node_printer(eo) { } void print_dot::print_infix(std::ostream& str, exptree::iterator it) { sibling_iterator lhs=tr.begin(it), rhs=lhs; ++rhs; if(parent.output_format==exptree_output::out_xcadabra) str << "\\,"; parent.get_printer(lhs)->print_infix(str, lhs); if(parent.output_format==exptree_output::out_xcadabra || parent.output_format==exptree_output::out_texmacs ) str << "\\!\\cdot{}\\!"; else str << "."; parent.get_printer(rhs)->print_infix(str, rhs); if(parent.output_format==exptree_output::out_xcadabra) str << "\\,"; } print_pow::print_pow(exptree_output& eo) : node_printer(eo) { } void print_pow::print_infix(std::ostream& str, exptree::iterator it) { if(*it->multiplier!=1) print_multiplier(str, it); bool close_bracket=false; sibling_iterator st=tr.begin(it); // The first argument of \pow is to be examined for special // cases which require brackets around the entire argument. if(*st->name=="\\sum") { str << "("; close_bracket=true; } else if(tr.number_of_children(st)!=tr.number_of_indices(st)) { str << "("; close_bracket=true; } else if(*st->multiplier!=1) { str << "("; close_bracket=true; } sibling_iterator ch=tr.begin(it); parent.get_printer(ch)->print_infix(str, ch); if(close_bracket) str << ")"; if(parent.output_format==exptree_output::out_xcadabra) { str << "{}^{"; ++ch; parent.get_printer(ch)->print_infix(str, ch); str << "}"; } else { str << "**{"; ++ch; parent.get_printer(ch)->print_infix(str, ch); str << "}"; } } print_frac::print_frac(exptree_output& eo) : node_printer(eo) { } void print_frac::print_infix(std::ostream& str, exptree::iterator it) { sibling_iterator num=tr.begin(it), den=num; ++den; bool close_bracket=false; if(*it->multiplier!=1) { print_multiplier(str, it); str << "("; close_bracket=true; } if(parent.output_format==exptree_output::out_xcadabra) str << "\\frac{"; parent.get_printer(num)->print_infix(str, num); if(parent.output_format==exptree_output::out_xcadabra) str << "}{"; else str << "/"; parent.get_printer(den)->print_infix(str, den); if(parent.output_format==exptree_output::out_xcadabra) str << "}"; if(close_bracket) str << ")"; } print_sqrt::print_sqrt(exptree_output& eo) : node_printer(eo) { } void print_sqrt::print_infix(std::ostream& str, exptree::iterator it) { str << "\\sqrt{"; sibling_iterator arg=tr.begin(it); parent.get_printer(arg)->print_infix(str, arg); str << "}"; } print_sum::print_sum(exptree_output& eo) : node_printer(eo) { } void print_sum::print_infix(std::ostream& str, exptree::iterator it) { std::ostringstream lstr; // txtout << "length of sum=" << lstr.str().size() << std::endl; // do_actual_print(lstr, it); do_actual_print(str, it); } void print_sum::do_actual_print(std::ostream& str, exptree::iterator it) { bool close_bracket=false; if(*it->multiplier!=1) print_multiplier(str, it); iterator par=tr.parent(it); if(tr.number_of_children(par) - tr.number_of_direct_indices(par)>1) { // for a single argument, the parent already takes care of the brackets if(*it->multiplier!=1 || (tr.is_valid(par) && *par->name!="\\expression")) { // test whether we need extra brackets close_bracket=!children_have_brackets(it); if(close_bracket) str << "("; } } unsigned int steps=0; str_node::bracket_t previous_bracket_=str_node::b_invalid; sibling_iterator ch=tr.begin(it); bool beginning_of_group=true; bool mathematica_postponed_endl=false; while(ch!=tr.end(it)) { if(++steps==20) { if(parent.output_format==exptree_output::out_xcadabra) str << "%\n" << std::flush; // prevent LaTeX overflow steps=0; } str_node::bracket_t current_bracket_=(*ch).fl.bracket; if(previous_bracket_!=current_bracket_) if(current_bracket_!=str_node::b_none) { if(ch!=tr.begin(it)) { if(parent.tight_plus) str << "+"; else if(parent.utf8_output) str << " +" << unichar(0x00a0); else str << " + "; } print_opening_bracket(str, current_bracket_, str_node::p_none); beginning_of_group=true; } if(beginning_of_group) { beginning_of_group=false; if(*ch->multiplier<0) { if(parent.tight_plus) str << "-"; else if(parent.utf8_output) str << " -" << unichar(0x00a0); else str << " - "; } } else { if(*ch->multiplier<0) { if(parent.tight_plus) str << "-"; else if(parent.utf8_output) str << " -" << unichar(0x00a0); else str << " - "; } else { if(parent.tight_plus) str << "+"; else if(parent.utf8_output) str << " +" << unichar(0x00a0); else str << " + "; } } if(mathematica_postponed_endl) { str << std::endl; mathematica_postponed_endl=false; } if(*ch->name=="1" && (*ch->multiplier==1 || *ch->multiplier==-1)) str << "1"; // special case numerical constant else parent.get_printer(ch)->print_infix(str, ch); ++ch; if(ch==tr.end(it)) { if(current_bracket_!=str_node::b_none) print_closing_bracket(str, current_bracket_, str_node::p_none); } else { // if(current_bracket_!=(*ch).fl.bracket) // throw display_error(); // assert(current_bracket_==(*ch).fl.bracket); if(parent.bracket_level==0) { if(parent.output_format==exptree_output::out_mathematica) mathematica_postponed_endl=true; // FIXME: this endl should be re-inserted for nodes having line_per_node true // else // str << std::endl; } } previous_bracket_=current_bracket_; } if(close_bracket) str << ")"; str << std::flush; } print_equals::print_equals(exptree_output& eo) : node_printer(eo) { } void print_equals::print_infix(std::ostream& str, exptree::iterator it) { sibling_iterator lhs=tr.begin(it), rhs=lhs; ++rhs; parent.get_printer(lhs)->print_infix(str, lhs); if(parent.tight_plus) str << "="; else str << " = "; parent.get_printer(rhs)->print_infix(str, rhs); } print_unequals::print_unequals(exptree_output& eo) : node_printer(eo) { } void print_unequals::print_infix(std::ostream& str, exptree::iterator it) { sibling_iterator lhs=tr.begin(it), rhs=lhs; ++rhs; parent.get_printer(lhs)->print_infix(str, lhs); if(parent.tight_plus) str << " "; if(parent.output_format==exptree_output::out_xcadabra || parent.output_format==exptree_output::out_texmacs ) str << "\\not="; else str << "!="; if(parent.tight_plus) str << " "; parent.get_printer(rhs)->print_infix(str, rhs); } print_conditional::print_conditional(exptree_output& eo) : node_printer(eo) { } void print_conditional::print_infix(std::ostream& str, exptree::iterator it) { sibling_iterator lhs=tr.begin(it), rhs=lhs; ++rhs; parent.get_printer(lhs)->print_infix(str, lhs); if(parent.tight_plus) str << " "; if(parent.output_format==exptree_output::out_xcadabra || parent.output_format==exptree_output::out_texmacs ) str << " \\;\\vert\\; "; else str << "|"; if(parent.tight_plus) str << " "; parent.get_printer(rhs)->print_infix(str, rhs); } print_regex::print_regex(exptree_output& eo) : node_printer(eo) { } void print_regex::print_infix(std::ostream& str, exptree::iterator it) { if(parent.output_format!=exptree_output::out_xcadabra && parent.output_format!=exptree_output::out_texmacs ) return node_printer::print_infix(str, it); sibling_iterator lhs=tr.begin(it), rhs=lhs; ++rhs; parent.get_printer(lhs)->print_infix(str, lhs); if(parent.tight_plus) str << " "; str << " =_{\\cal R} "; if(parent.tight_plus) str << " "; parent.get_printer(rhs)->print_infix(str, rhs); } print_factorial::print_factorial(exptree_output& eo) : node_printer(eo) { } void print_factorial::print_infix(std::ostream& str, exptree::iterator it) { sibling_iterator arg=tr.begin(it); parent.get_printer(arg)->print_infix(str, arg); str << "!"; } print_comma::print_comma(exptree_output& eo) : node_printer(eo) { } void print_comma::print_infix(std::ostream& str, exptree::iterator it) { sibling_iterator ch=tr.begin(it); if(! (tr.begin(it)->fl.bracket==str_node::b_none && it->fl.bracket!=str_node::b_none) ) { switch(tr.begin(it)->fl.bracket) { case str_node::b_none: str << "\\{"; break; case str_node::b_pointy: str << "\\<"; break; case str_node::b_curly: str << "\\{"; break; case str_node::b_round: str << "("; break; case str_node::b_square: str << "["; break; default : return; } ++(parent.bracket_level); } while(ch!=tr.end(it)) { parent.get_printer(ch)->print_infix(str, ch); ++ch; if(ch!=tr.end(it)) { str << ","; if(!parent.tight_plus) { if(parent.output_format==exptree_output::out_xcadabra) str << "\\; "; else str << " "; // FIXME: print extra endl depending on line_per_node // if(parent.bracket_level==1) // str << std::endl; } } } if(! (tr.begin(it)->fl.bracket==str_node::b_none && it->fl.bracket!=str_node::b_none) ) { switch(tr.begin(it)->fl.bracket) { case str_node::b_none: str << "\\}"; break; case str_node::b_pointy: str << "\\>"; break; case str_node::b_curly: str << "\\}"; break; case str_node::b_round: str << ")"; break; case str_node::b_square: str << "]"; break; default : return; } --(parent.bracket_level); } } print_tableau::print_tableau(exptree_output& eo) : node_printer(eo) { } void print_tableau::print_infix(std::ostream& str, exptree::iterator it) { if(*it->multiplier!=1) print_multiplier(str, it); str << "\\tableau{"; sibling_iterator sib=tr.begin(it); bool first=true; while(sib!=tr.end(it)) { if(!first) str << " "; else first=false; str << *sib->multiplier; ++sib; } str << "}" << std::endl; } print_filled_tableau::print_filled_tableau(exptree_output& eo) : node_printer(eo) { } void print_filled_tableau::print_infix(std::ostream& str, exptree::iterator it) { if(*it->multiplier!=1) print_multiplier(str, it); str << "\\ftableau{"; sibling_iterator sib=tr.begin(it); bool first=true; while(sib!=tr.end(it)) { if(!first) str << ","; else first=false; if(*sib->name=="\\comma") { sibling_iterator sib2=tr.begin(sib); while(sib2!=tr.end(sib)) { str << "{"; parent.get_printer(sib2)->print_infix(str, sib2); str << "}"; ++sib2; } } else { str << "{"; parent.get_printer(sib)->print_infix(str, sib); str << "}"; } ++sib; } str << "}" << std::endl; } print_derivative::print_derivative(exptree_output& eo) : node_printer(eo) { } void print_derivative::print_infix(std::ostream& str, exptree::iterator it) { if(*it->multiplier!=1) print_multiplier(str, it); const LaTeXForm *lf=properties::get(it); bool needs_extra_brackets=false; if(parent.output_format==exptree_output::out_xcadabra) { const Accent *ac=properties::get(it); if(!ac) { // accents should never get additional curly brackets, {\bar}{g} does not print. sibling_iterator sib=tr.begin(it); while(sib!=tr.end(it)) { if(sib->is_index()) needs_extra_brackets=true; ++sib; } } if(needs_extra_brackets) str << "{"; // to prevent double sup/sub script errors if(lf) str << lf->latex; else str << texify(*it->name); if(needs_extra_brackets) str << "}"; } else str << *it->name; sibling_iterator idx=tr.begin(it); int count=0; previous_parent_rel_=str_node::p_none; while(idx!=tr.end(it)) { sibling_iterator nxt=idx; ++nxt; if(idx->is_index()) { if(idx->fl.parent_rel!=previous_parent_rel_) { print_parent_rel(str, idx->fl.parent_rel, idx==tr.begin(it)); str << "{"; previous_parent_rel_=idx->fl.parent_rel; parent.get_printer(idx)->print_infix(str, idx); } else parent.get_printer(idx)->print_infix(str, idx); if(nxt==tr.end(it) || nxt->fl.parent_rel!=previous_parent_rel_) str << "}"; else str << " "; } else { str << "{"; if(*idx->name=="\\prod" || *idx->name=="\\sum") str << "("; parent.get_printer(idx)->print_infix(str, idx); if(*idx->name=="\\prod" || *idx->name=="\\sum") str << ")"; str << "}"; } ++idx; ++count; } if(parent.output_format==exptree_output::out_xcadabra) str << "\\, "; } print_sequence::print_sequence(exptree_output& eo) : node_printer(eo) { } void print_sequence::print_infix(std::ostream& str, exptree::iterator it) { sibling_iterator ch=tr.begin(it); parent.get_printer(ch)->print_infix(str, ch); str << ".."; ++ch; parent.get_printer(ch)->print_infix(str, ch); } print_commutator::print_commutator(exptree_output& eo) : node_printer(eo) { } void print_commutator::print_infix(std::ostream& str, exptree::iterator it) { bool prettyform; if(parent.output_format!=exptree_output::out_xcadabra && parent.output_format!=exptree_output::out_texmacs ) prettyform=false; else prettyform=true; bool anticommutator=true; if(*it->name=="\\commutator") anticommutator=false; if(*it->multiplier!=1) print_multiplier(str, it); sibling_iterator ch=tr.begin(it); if(prettyform) { if(anticommutator) str << "\\{"; else str << "["; } else { str << *it->name << "{"; } parent.get_printer(ch)->print_infix(str, ch); if(prettyform) str << ","; else str << "}{"; ++ch; parent.get_printer(ch)->print_infix(str, ch); if(prettyform) { if(anticommutator) str << "\\}"; else str << "]"; } else str << "}"; } print_indexbracket::print_indexbracket(exptree_output& eo) : node_printer(eo) { } void print_indexbracket::print_infix(std::ostream& str, exptree::iterator it) { // iterator arg=tr.begin(it); // if(*arg->name!="\\sum" && *arg->name!="\\prod") { // if(children_have_brackets(it)) // print_opening_bracket(str,arg->fl.bracket); // } // else { // if(!children_have_brackets(tr.begin(it))) str << "("; // } parent.get_printer(tr.begin(it))->print_infix(str, tr.begin(it)); // if(*arg->name!="\\sum" && *arg->name!="\\prod") { // if(children_have_brackets(it)) // print_closing_bracket(str,arg->fl.bracket); // } // else { // if(!children_have_brackets(tr.begin(it))) str << ")"; // } print_children(str, it, 1); } /* --------------------------------------------------------------------- */ print_mathml_expression::print_mathml_expression(exptree_output& eo) : mathml_node_printer(eo) { } void print_mathml_expression::print_infix(std::ostream& str, iterator it) { str << "" << std::endl; parent.get_printer(tr.begin(it))->print_infix(str, tr.begin(it)); str << ""; } print_mathml_productlike::print_mathml_productlike(exptree_output& eo) : mathml_node_printer(eo) { } print_mathml_wedge::print_mathml_wedge(exptree_output& eo) : print_mathml_productlike(eo) { } void print_mathml_wedge::print_infix(std::ostream&, iterator) { } print_mathml_prod::print_mathml_prod(exptree_output& eo) : print_mathml_productlike(eo) { } void print_mathml_prod::print_infix(std::ostream&, iterator) { } print_mathml_indexbracket::print_mathml_indexbracket(exptree_output& eo) : mathml_node_printer(eo) { } void print_mathml_indexbracket::print_infix(std::ostream&, iterator) { } print_mathml_pow::print_mathml_pow(exptree_output& eo) : mathml_node_printer(eo) { } void print_mathml_pow::print_infix(std::ostream&, iterator) { } print_mathml_frac::print_mathml_frac(exptree_output& eo) : mathml_node_printer(eo) { } void print_mathml_frac::print_infix(std::ostream&, iterator) { } print_mathml_sum::print_mathml_sum(exptree_output& eo) : mathml_node_printer(eo) { } void print_mathml_sum::print_infix(std::ostream&, iterator) { } print_mathml_sequence::print_mathml_sequence(exptree_output& eo) : mathml_node_printer(eo) { } void print_mathml_sequence::print_infix(std::ostream&, iterator) { } print_mathml_equals::print_mathml_equals(exptree_output& eo) : mathml_node_printer(eo) { } void print_mathml_equals::print_infix(std::ostream&, iterator) { } print_mathml_unequals::print_mathml_unequals(exptree_output& eo) : mathml_node_printer(eo) { } void print_mathml_unequals::print_infix(std::ostream&, iterator) { } print_mathml_factorial::print_mathml_factorial(exptree_output& eo) : mathml_node_printer(eo) { } void print_mathml_factorial::print_infix(std::ostream&, iterator) { } print_mathml_comma::print_mathml_comma(exptree_output& eo) : mathml_node_printer(eo) { } void print_mathml_comma::print_infix(std::ostream&, iterator) { } /* --------------------------------------------------------------------- */ node_base_printer::node_base_printer(exptree_output& eo) : parent(eo), tr(eo.tr) { } bool node_base_printer::children_have_brackets(iterator ch) const { sibling_iterator chlds=tr.begin(ch); str_node::bracket_t childbr=chlds->fl.bracket; if(childbr==str_node::b_none || childbr==str_node::b_no) return false; else return true; } /* --------------------------------------------------------------------- */ node_printer::node_printer(exptree_output& eo) : node_base_printer(eo), isdelta(false), isweyl(false) { } void node_printer::print_infix(std::ostream& str, exptree::iterator it) { // print multiplier and object name if(*it->multiplier!=1) print_multiplier(str, it); if(*it->name=="1") { if(*it->multiplier==1 || (*it->multiplier==-1)) // this would print nothing altogether. str << "1"; return; } if(parent.output_format==exptree_output::out_xcadabra) { const LaTeXForm *lf=properties::get(it); bool needs_extra_brackets=false; const Accent *ac=properties::get(it); if(!ac) { // accents should never get additional curly brackets, {\bar}{g} does not print. sibling_iterator sib=tr.begin(it); while(sib!=tr.end(it)) { if(sib->is_index()) needs_extra_brackets=true; ++sib; } } if(needs_extra_brackets) str << "{"; // to prevent double sup/sub script errors if(lf) str << lf->latex; else str << texify(*it->name); if(needs_extra_brackets) str << "}"; } else str << *it->name; print_children(str, it); } std::string node_printer::texify(const std::string& str) const { std::string res; for(unsigned int i=0; iis_index()==false) { ++number_of_nonindex_children; if(*ch->name=="\\prod") ++number_of_nonindex_children; } else ++number_of_index_children; ++ch; } ch=tr.begin(it); ch+=skip; unsigned int chnum=0; while(ch!=tr.end(it)) { current_bracket_ =(*ch).fl.bracket; current_parent_rel_=(*ch).fl.parent_rel; const Accent *is_accent=properties::get(it); if(current_bracket_!=str_node::b_none || previous_bracket_!=current_bracket_ || previous_parent_rel_!=current_parent_rel_) { if(parent.output_format==exptree_output::out_plain || parent.output_format==exptree_output::out_xcadabra || parent.output_format==exptree_output::out_texmacs ) print_parent_rel(str, current_parent_rel_, ch==tr.begin(it)); if(parent.output_format!=exptree_output::out_reduce) { if(is_accent==0) print_opening_bracket(str, (number_of_nonindex_children>1 /* &&number_of_index_children>0 */ && current_parent_rel_!=str_node::p_sub && current_parent_rel_!=str_node::p_super ? str_node::b_round:current_bracket_), current_parent_rel_); else str << "{"; } else str << zwnbsp << "(" << zwnbsp; } if(parent.output_format==exptree_output::out_mathematica && getenv("CDB_MATH_COMPAC")==0) { if(ch!=tr.begin(it)) { if(chnum==2 && isweyl) str << "}," << nbsp << "{"; else str << "," << nbsp; } } else if(parent.output_format==exptree_output::out_reduce) { if(ch!=tr.begin(it)) str << "," << zwnbsp; } parent.get_printer(ch)->print_infix(str, ch); // if((*it).fl.mark && parent.highlight) str << "\033[1m"; ++ch; if(ch==tr.end(it) || current_bracket_!=str_node::b_none || current_bracket_!=(*ch).fl.bracket || current_parent_rel_!=(*ch).fl.parent_rel) { if(parent.output_format!=exptree_output::out_reduce) { if(is_accent==0) print_closing_bracket(str, (number_of_nonindex_children>1 /* &&number_of_index_children>0 */ && current_parent_rel_!=str_node::p_sub && current_parent_rel_!=str_node::p_super ? str_node::b_round:current_bracket_), current_parent_rel_); else str << "}"; } else str << ")"; } else if(parent.output_format==exptree_output::out_plain || parent.output_format==exptree_output::out_xcadabra || parent.output_format==exptree_output::out_maple || parent.output_format==exptree_output::out_texmacs) str << nbsp; previous_bracket_=current_bracket_; previous_parent_rel_=current_parent_rel_; ++chnum; } } void node_printer::print_multiplier(std::ostream& str, exptree::iterator it) { bool turned_one=false; mpz_class denom=it->multiplier->get_den(); if(*it->multiplier<0) { if(*tr.parent(it)->name=="\\sum") { // sum takes care of minus sign if(*it->multiplier!=-1) { if(denom!=1 && ( parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra) ) { str << "\\frac{" << -(it->multiplier->get_num()) << "}{" << it->multiplier->get_den() << "}"; } else { str << -(*it->multiplier); } } else turned_one=true; } else { if(denom!=1 && ( parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra) ) { str << "(\\frac{" << it->multiplier->get_num() << "}{" << it->multiplier->get_den() << "})"; } else if(*it->multiplier==-1) { str << "-"; turned_one=true; } else { str << "(" << *it->multiplier << ")"; } } } else { if(denom!=1 && (parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra) ) { str << "\\frac{" << it->multiplier->get_num() << "}{" << it->multiplier->get_den() << "}"; } else str << *it->multiplier; } if(!turned_one && !(*it->name=="1")) { if(parent.print_star && !(parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra) ) { if(parent.tight_star) str << "*"; else if(parent.utf8_output) str << unichar(0x00a0) << "*" << unichar(0x00a0); else str << " * "; } else { if(!parent.tight_star) { if(parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra ) str << "\\, "; else str << " "; } } } } void node_printer::print_opening_bracket(std::ostream& str, str_node::bracket_t br, str_node::parent_rel_t pr) { switch(br) { case str_node::b_none: if(parent.output_format==exptree_output::out_xcadabra && pr==str_node::p_none) str << "("; else str << "{"; break; case str_node::b_pointy: str << "\\<"; break; case str_node::b_curly: str << "\\{"; break; case str_node::b_round: str << "("; break; case str_node::b_square: str << "["; break; default : return; } ++(parent.bracket_level); } void node_printer::print_closing_bracket(std::ostream& str, str_node::bracket_t br, str_node::parent_rel_t pr) { switch(br) { case str_node::b_none: if(parent.output_format==exptree_output::out_xcadabra && pr==str_node::p_none) str << ")"; else str << "}"; break; case str_node::b_pointy: str << "\\>"; break; case str_node::b_curly: str << "\\}"; break; case str_node::b_round: str << ")"; break; case str_node::b_square: str << "]"; break; default : return; } --(parent.bracket_level); } void node_printer::print_parent_rel(std::ostream& str, str_node::parent_rel_t pr, bool first) { switch(pr) { case str_node::p_super: if(!first && (parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra) ) str << "\\,"; str << "^"; break; case str_node::p_sub: if(!first && (parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra)) str << "\\,"; str << "_"; break; case str_node::p_property: str << "$"; break; case str_node::p_exponent: str << "**"; break; case str_node::p_none: break; } // Prevent line break after this character. str << zwnbsp; } void exptree_output::print_full_standardform(std::ostream& str, exptree::iterator it, bool eqno) { if(eqno) { nset_t::iterator name=tr.equation_label(it); if(xml_structured) str << "" << std::endl; if(name!=name_set.end()) str << *name; else str << tr.equation_number(it); if(!xml_structured) str << ":= "; else str << std::endl << "" << std::endl; } if(output_format==exptree_output::out_xcadabra) { // first output plain output_format=exptree_output::out_plain; str << "" << std::endl; print_infix(str, tr.active_expression(it)); str << std::endl << "" << std::endl; output_format=exptree_output::out_xcadabra; } if(xml_structured) str << "" << std::endl; print_infix(str, tr.active_expression(it)); str << ";"; if(output_format==exptree_output::out_plain) str << std::endl; if(xml_structured) str << std::endl << "" << std::endl; } /* ----------------------------------------------------------------------- */ mathml_node_printer::mathml_node_printer(exptree_output& eo) : node_base_printer(eo) { } void mathml_node_printer::print_infix(std::ostream& str, exptree::iterator it) { // if((*it).fl.mark && parent.highlight) str << "\033[1m"; // print multiplier and object name if(*it->multiplier!=1) print_multiplier(str, it); if(*it->name=="1") { if(*it->multiplier==1) // this would print nothing altogether. str << "1"; return; } str << *it->name; print_children(str, it); } void mathml_node_printer::print_children(std::ostream& str, exptree::iterator it, int skip) { previous_bracket_ =str_node::b_invalid; previous_parent_rel_=str_node::p_none; int number_of_nonindex_children=0; int number_of_index_children=0; exptree::sibling_iterator ch=tr.begin(it); while(ch!=tr.end(it)) { if(ch->is_index()==false) { ++number_of_nonindex_children; if(*ch->name=="\\prod") ++number_of_nonindex_children; } else ++number_of_index_children; ++ch; } ch=tr.begin(it); ch+=skip; unsigned int chnum=0; while(ch!=tr.end(it)) { current_bracket_ =(*ch).fl.bracket; current_parent_rel_=(*ch).fl.parent_rel; if(current_bracket_!=str_node::b_none || previous_bracket_!=current_bracket_ || previous_parent_rel_!=current_parent_rel_) { if(parent.output_format==exptree_output::out_plain || parent.output_format==exptree_output::out_xcadabra || parent.output_format==exptree_output::out_texmacs) print_parent_rel(str, current_parent_rel_, ch==tr.begin(it)); if(parent.output_format!=exptree_output::out_reduce) print_opening_bracket(str, (number_of_nonindex_children>1 && number_of_index_children>0 && current_parent_rel_!=str_node::p_sub && current_parent_rel_!=str_node::p_super ? str_node::b_round:current_bracket_), current_parent_rel_); else str << zwnbsp << "(" << zwnbsp; } if(parent.output_format==exptree_output::out_mathematica && getenv("CDB_MATH_COMPAC")==0) { if(ch!=tr.begin(it)) { str << "," << nbsp; } } else if(parent.output_format==exptree_output::out_reduce) { if(ch!=tr.begin(it)) str << "," << zwnbsp; } parent.get_printer(ch)->print_infix(str, ch); // if((*it).fl.mark && parent.highlight) str << "\033[1m"; ++ch; if(ch==tr.end(it) || current_bracket_!=str_node::b_none || current_bracket_!=(*ch).fl.bracket || current_parent_rel_!=(*ch).fl.parent_rel) { if(parent.output_format!=exptree_output::out_reduce) print_closing_bracket(str, (number_of_nonindex_children>1 && number_of_index_children>0 && current_parent_rel_!=str_node::p_sub && current_parent_rel_!=str_node::p_super ? str_node::b_round:current_bracket_), current_parent_rel_); else str << ")"; } else if(parent.output_format==exptree_output::out_plain || parent.output_format==exptree_output::out_xcadabra || parent.output_format==exptree_output::out_maple || parent.output_format==exptree_output::out_texmacs) str << nbsp; previous_bracket_=current_bracket_; previous_parent_rel_=current_parent_rel_; ++chnum; } if(parent.output_format==exptree_output::out_mathematica && it->fl.parent_rel==str_node::p_none && tr.number_of_children(it)>0) str << "]"; // if((*it).fl.mark && parent.highlight) str << "\033[0m"; } void mathml_node_printer::print_multiplier(std::ostream& str, exptree::iterator it) { bool turned_one=false; mpz_class denom=it->multiplier->get_den(); if(*it->multiplier<0) { if(*tr.parent(it)->name=="\\sum") { // sum takes care of minus sign if(*it->multiplier!=-1) { if(denom!=1 && (parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra) ) { str << "\\frac{" << -(it->multiplier->get_num()) << "}{" << it->multiplier->get_den() << "}"; } else { str << -(*it->multiplier); } } else turned_one=true; } else { if(denom!=1 && (parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra) ) { str << "(\\frac{" << it->multiplier->get_num() << "}{" << it->multiplier->get_den() << "})"; } else { str << "(" << *it->multiplier << ")"; } } } else { if(denom!=1 && (parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra) ) { str << "\\frac{" << it->multiplier->get_num() << "}{" << it->multiplier->get_den() << "}"; } else str << *it->multiplier; } if(!turned_one && !(*it->name=="1")) { if(parent.print_star && !(parent.output_format==exptree_output::out_texmacs) && !(parent.output_format==exptree_output::out_xcadabra) ) { if(parent.tight_star) str << "*"; else if(parent.utf8_output) str << unichar(0x00a0) << "*" << unichar(0x00a0); else str << " * "; } else { if(!parent.tight_star) { if(parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra ) str << "\\, "; else str << " "; } } } } void mathml_node_printer::print_opening_bracket(std::ostream& str, str_node::bracket_t br, str_node::parent_rel_t pr) { switch(br) { case str_node::b_none: str << "{"; break; case str_node::b_pointy: str << "\\<"; break; case str_node::b_curly: str << "\\{"; break; case str_node::b_round: str << "("; break; case str_node::b_square: str << "["; break; default : return; } ++(parent.bracket_level); } void mathml_node_printer::print_closing_bracket(std::ostream& str, str_node::bracket_t br, str_node::parent_rel_t pr) { switch(br) { case str_node::b_none: str << "}"; break; case str_node::b_pointy: str << "\\>"; break; case str_node::b_curly: str << "\\}"; break; case str_node::b_round: str << ")"; break; case str_node::b_square: str << "]"; break; default : return; } --(parent.bracket_level); } void mathml_node_printer::print_parent_rel(std::ostream& str, str_node::parent_rel_t pr, bool first) { switch(pr) { case str_node::p_super: if(!first && ( parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra) ) str << "\\,"; str << "^"; break; case str_node::p_sub: if(!first && ( parent.output_format==exptree_output::out_texmacs || parent.output_format==exptree_output::out_xcadabra) ) str << "\\,"; str << "_"; break; case str_node::p_property: str << "$"; break; case str_node::p_exponent: str << "**"; break; case str_node::p_none: break; } // Prevent line break after this character. str << zwnbsp; } /* ----------------------------------------------------------------------- */ // Thanks to Behdad Esfahbod int k_unichar_to_utf8(kunichar c, char *buf) { buf[0]=(c) < 0x00000080 ? (c) : (c) < 0x00000800 ? ((c) >> 6) | 0xC0 : (c) < 0x00010000 ? ((c) >> 12) | 0xE0 : (c) < 0x00200000 ? ((c) >> 18) | 0xF0 : (c) < 0x04000000 ? ((c) >> 24) | 0xF8 : ((c) >> 30) | 0xFC; buf[1]=(c) < 0x00000080 ? 0 /* null-terminator */ : (c) < 0x00000800 ? ((c) & 0x3F) | 0x80 : (c) < 0x00010000 ? (((c) >> 6) & 0x3F) | 0x80 : (c) < 0x00200000 ? (((c) >> 12) & 0x3F) | 0x80 : (c) < 0x04000000 ? (((c) >> 18) & 0x3F) | 0x80 : (((c) >> 24) & 0x3F) | 0x80; buf[2]=(c) < 0x00000800 ? 0 /* null-terminator */ : (c) < 0x00010000 ? ((c) & 0x3F) | 0x80 : (c) < 0x00200000 ? (((c) >> 6) & 0x3F) | 0x80 : (c) < 0x04000000 ? (((c) >> 12) & 0x3F) | 0x80 : (((c) >> 18) & 0x3F) | 0x80; buf[3]=(c) < 0x00010000 ? 0 /* null-terminator */ : (c) < 0x00200000 ? ((c) & 0x3F) | 0x80 : (c) < 0x04000000 ? (((c) >> 6) & 0x3F) | 0x80 : (((c) >> 12) & 0x3F) | 0x80; buf[4]=(c) < 0x00200000 ? 0 /* null-terminator */ : (c) < 0x04000000 ? ((c) & 0x3F) | 0x80 : (((c) >> 6) & 0x3F) | 0x80; buf[5]=(c) < 0x04000000 ? 0 /* null-terminator */ : ((c) & 0x3F) | 0x80; buf[6]=0; return 6; } const char *unichar(kunichar c) { static char buffer[7]; int pos=k_unichar_to_utf8(c, buffer); buffer[pos]=0; return buffer; } cadabra-1.39/src/display.hh000066400000000000000000000273761234107666300156270ustar00rootroot00000000000000/* Cadabra: a field-theory motivated computer algebra system. Copyright (C) 2001-2011 Kasper Peeters 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 3 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, see . */ #ifndef display_hh_ #define display_hh_ #include "storage.hh" //#include "modules/properties.hh" #include typedef uint32_t kunichar; // TeXmacs markers #define DATA_BEGIN ((char) 2) #define DATA_END ((char) 5) #define DATA_COMMAND ((char) 16) #define DATA_ESCAPE ((char) 27) class exptree_output; class display_error { public: display_error(); }; class display_interrupted { public: display_interrupted(); }; /// The base class for displaying/printing nodes in the expression /// tree. class node_base_printer { public: typedef exptree::iterator iterator; typedef exptree::sibling_iterator sibling_iterator; node_base_printer(exptree_output&); virtual ~node_base_printer() {}; virtual void print_infix(std::ostream&, iterator) = 0; protected: exptree_output& parent; const exptree& tr; str_node::parent_rel_t previous_parent_rel_, current_parent_rel_; str_node::bracket_t previous_bracket_, current_bracket_; // Determine whether the children of the indicated node all have // the same, non-empty bracket type (i.e. determines whether, when // the indicated node is a \\sum, the children will automatically // be wrapped in a bracket). bool children_have_brackets(iterator) const; }; /// The default printing class for standard text output to the console. /// Also contains logic for printing in Mathematica and Maple format, /// to be split off in a separate class hierarchy later. class node_printer : public node_base_printer { public: node_printer(exptree_output&); virtual ~node_printer() {}; virtual void print_infix(std::ostream&, iterator); protected: void print_multiplier(std::ostream&, exptree::iterator); void print_opening_bracket(std::ostream&, str_node::bracket_t, str_node::parent_rel_t); void print_closing_bracket(std::ostream&, str_node::bracket_t, str_node::parent_rel_t); void print_parent_rel(std::ostream&, str_node::parent_rel_t, bool first); void print_children(std::ostream&, exptree::iterator, int skip=0); std::string texify(const std::string&) const; // some random junk variables bool isdelta; bool isweyl; }; /// The default node printing class for MathML output. class mathml_node_printer : public node_base_printer { public: mathml_node_printer(exptree_output&); virtual ~mathml_node_printer() {}; virtual void print_infix(std::ostream&, iterator); protected: void print_multiplier(std::ostream&, exptree::iterator); void print_opening_bracket(std::ostream&, str_node::bracket_t, str_node::parent_rel_t); void print_closing_bracket(std::ostream&, str_node::bracket_t, str_node::parent_rel_t); void print_parent_rel(std::ostream&, str_node::parent_rel_t, bool first); void print_children(std::ostream&, exptree::iterator, int skip=0); }; /* ------------------------------------------------------------------------------- */ class print_expression : public node_printer { public: print_expression(exptree_output&); virtual ~print_expression() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_productlike : public node_printer { public: print_productlike(exptree_output&); virtual ~print_productlike() {}; protected: void doprint(std::ostream&, exptree::iterator, const std::string&); }; class print_wedge : public print_productlike { public: print_wedge(exptree_output&); virtual ~print_wedge() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_prod : public print_productlike { public: print_prod(exptree_output&); virtual ~print_prod() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_dot : public node_printer { public: print_dot(exptree_output&); virtual ~print_dot() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_sqrt : public node_printer { public: print_sqrt(exptree_output&); virtual ~print_sqrt() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_arrow : public node_printer { public: print_arrow(exptree_output&); virtual ~print_arrow() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_commutator : public node_printer { public: print_commutator(exptree_output&); virtual ~print_commutator() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_indexbracket : public node_printer { public: print_indexbracket(exptree_output&); virtual ~print_indexbracket() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_pow : public node_printer { public: print_pow(exptree_output&); virtual ~print_pow() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_frac : public node_printer { public: print_frac(exptree_output&); virtual ~print_frac() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_sum : public node_printer { public: print_sum(exptree_output&); virtual ~print_sum() {}; virtual void print_infix(std::ostream&, iterator ); private: void do_actual_print(std::ostream&, iterator); }; class print_sequence : public node_printer { public: print_sequence(exptree_output&); virtual ~print_sequence() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_equals : public node_printer { public: print_equals(exptree_output&); virtual ~print_equals() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_unequals : public node_printer { public: print_unequals(exptree_output&); virtual ~print_unequals() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_conditional : public node_printer { public: print_conditional(exptree_output&); virtual ~print_conditional() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_regex : public node_printer { public: print_regex(exptree_output&); virtual ~print_regex() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_factorial : public node_printer { public: print_factorial(exptree_output&); virtual ~print_factorial() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_comma : public node_printer { public: print_comma(exptree_output&); virtual ~print_comma() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_tableau : public node_printer { public: print_tableau(exptree_output&); virtual ~print_tableau() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_filled_tableau : public node_printer { public: print_filled_tableau(exptree_output&); virtual ~print_filled_tableau() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_derivative : public node_printer { public: print_derivative(exptree_output&); virtual ~print_derivative() {}; virtual void print_infix(std::ostream&, iterator ); }; /* ------------------------------------------------------------------------------- */ class print_mathml_expression : public mathml_node_printer { public: print_mathml_expression(exptree_output&); virtual ~print_mathml_expression() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_mathml_productlike : public mathml_node_printer { public: print_mathml_productlike(exptree_output&); virtual ~print_mathml_productlike() {}; protected: void doprint(std::ostream&, exptree::iterator, const std::string&); }; class print_mathml_wedge : public print_mathml_productlike { public: print_mathml_wedge(exptree_output&); virtual ~print_mathml_wedge() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_mathml_prod : public print_mathml_productlike { public: print_mathml_prod(exptree_output&); virtual ~print_mathml_prod() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_mathml_indexbracket : public mathml_node_printer { public: print_mathml_indexbracket(exptree_output&); virtual ~print_mathml_indexbracket() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_mathml_pow : public mathml_node_printer { public: print_mathml_pow(exptree_output&); virtual ~print_mathml_pow() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_mathml_frac : public mathml_node_printer { public: print_mathml_frac(exptree_output&); virtual ~print_mathml_frac() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_mathml_sum : public mathml_node_printer { public: print_mathml_sum(exptree_output&); virtual ~print_mathml_sum() {}; virtual void print_infix(std::ostream&, iterator ); private: void do_actual_print(std::ostream&, iterator); }; class print_mathml_sequence : public mathml_node_printer { public: print_mathml_sequence(exptree_output&); virtual ~print_mathml_sequence() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_mathml_equals : public mathml_node_printer { public: print_mathml_equals(exptree_output&); virtual ~print_mathml_equals() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_mathml_unequals : public mathml_node_printer { public: print_mathml_unequals(exptree_output&); virtual ~print_mathml_unequals() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_mathml_factorial : public mathml_node_printer { public: print_mathml_factorial(exptree_output&); virtual ~print_mathml_factorial() {}; virtual void print_infix(std::ostream&, iterator ); }; class print_mathml_comma : public mathml_node_printer { public: print_mathml_comma(exptree_output&); virtual ~print_mathml_comma() {}; virtual void print_infix(std::ostream&, iterator ); }; /* ------------------------------------------------------------------------------- */ class exptree_output { public: enum output_format_t { out_plain, out_mathematica, out_reduce, out_maple, out_texmacs, out_mathml, out_xcadabra }; exptree_output(const exptree&, output_format_t of=out_plain); bool highlight; const bool tight_star; const bool tight_plus; const bool tight_brackets; bool print_star; output_format_t output_format; bool xml_structured; bool utf8_output; bool print_expression_number; const exptree& tr; void print_full_standardform(std::ostream&, exptree::iterator, bool eqno); void print_infix(std::ostream&, exptree::iterator); void print_prefix(std::ostream&, exptree::iterator); void setup_handlers(bool infix=true); void newline(std::ostream&); std::auto_ptr get_printer(exptree::iterator); unsigned int bracket_level; // FIXME: perhaps a stack? private: typedef std::map (*)(exptree_output&)> printmap_t; typedef std::map (*)(exptree_output&)> printmap_prop_t; printmap_t printers_; printmap_prop_t printers_prop_; std::auto_ptr (*print_default_)(exptree_output&); }; template std::auto_ptr create(exptree_output& eo) { return std::auto_ptr(new T(eo)); } const char *unichar(kunichar c); #endif cadabra-1.39/src/engine.hh000066400000000000000000000016131234107666300154110ustar00rootroot00000000000000/* Cadabra: a field-theory motivated computer algebra system. Copyright (C) 2001-2013 Kasper Peeters 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 3 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, see . */ /// This is the class which handles calls the algorithm objects /// to perform action on the expression tree. class engine { }; cadabra-1.39/src/exchange.cc000066400000000000000000000251731234107666300157230ustar00rootroot00000000000000/* Cadabra: a field-theory motivated computer algebra system. Copyright (C) 2001-2011 Kasper Peeters 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 3 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, see . */ #include "exchange.hh" #include "modules/algebra.hh" #include "modules/gamma.hh" #include "modules/lie.hh" #include "modules/numerical.hh" #include // Find groups of identical tensors. // int exchange::collect_identical_tensors(exptree& tr, exptree::iterator it, std::vector& idts) { assert(*it->name=="\\prod"); int total_number_of_indices=0; // refers to number of indices on gamma matrices exptree::sibling_iterator sib=it.begin(); while(sib!=it.end()) { unsigned int i=0; if(exptree::number_of_indices(sib)==0) { ++sib; continue; } if(properties::get_composite(sib)) { total_number_of_indices+=tr.number_of_indices(sib); ++sib; continue; } // In case of spinors, the name may be hidden inside a Dirac bar. exptree::sibling_iterator truetensor=sib; const DiracBar *db=properties::get_composite(truetensor); if(db) truetensor=tr.begin(truetensor); // Compare the current tensor with all other tensors encountered so far. for(; i(truetensor2); if(db2) truetensor2=tr.begin(truetensor2); if(subtree_equal(truetensor2, truetensor)) { // If this is a spinor, check that it's connected to the one already stored // by a Gamma matrix, or that it is connected directly. if(idts[i].spino) { exptree::sibling_iterator tmpit=idts[i].tensors[0]; const GammaMatrix *gmnxt=0; const Spinor *spnxt=0; // skip objects without spinor line do { ++tmpit; gmnxt=properties::get_composite(tmpit); spnxt=properties::get_composite(tmpit); } while(gmnxt==0 && spnxt==0); if(tmpit==sib) { // txtout << "using fermi exchange" << std::endl; idts[i].extra_sign++; break; } if(gmnxt) { // txtout << "gamma next " << std::endl; int numind=exptree::number_of_indices(tmpit); // skip objects without spinor line do { ++tmpit; gmnxt=properties::get_composite(tmpit); spnxt=properties::get_composite(tmpit); } while(gmnxt==0 && spnxt==0); if(tmpit==sib) { // yes, it's a proper Majorana spinor pair. // txtout << "using fermi exchange with gamma " << numind << std::endl; if( ((numind*(numind+1))/2)%2 == 0 ) idts[i].extra_sign++; break; } } } else break; } } if(i==idts.size()) { identical_tensors_t ngr; ngr.comm=properties::get_composite(sib, true); ngr.spino=properties::get_composite(sib); ngr.tab=properties::get_composite(sib); ngr.traceless=properties::get_composite(sib); ngr.gammatraceless=properties::get_composite(sib); ngr.extra_sign=0; ngr.number_of_indices=exptree::number_of_indices(truetensor); ngr.tensors.push_back(sib); ngr.seq_numbers_of_first_indices.push_back(total_number_of_indices); total_number_of_indices+=ngr.number_of_indices; if(ngr.spino==false || ngr.spino->majorana==true) idts.push_back(ngr); } else { idts[i].tensors.push_back(sib); idts[i].seq_numbers_of_first_indices.push_back(total_number_of_indices); total_number_of_indices+=idts[i].number_of_indices; } ++sib; } return total_number_of_indices; } unsigned int exchange::possible_singlets(exptree& tr, exptree::iterator it) { std::vector idts; collect_identical_tensors(tr, it, idts); if(idts.size()==0) return 1; // no indices, so this is a singlet already LiE::LiE_t lie; // Figure out the algebra from one of the indices. exptree::index_iterator indit=tr.begin_index(idts[0].tensors[0]); const numerical::Integer *iprop=properties::get(indit, true); if(!iprop) throw consistency_error("Need to know about the range of the " + *indit->name + " index."); // iprop->difference.print_recursive_treeform(txtout, iprop->difference.begin()); unsigned int dims=to_long(*iprop->difference.begin()->multiplier); // std::cout << "*** " << dims << std::endl; if(dims%2==0) lie.algebra_type=LiE::LiE_t::alg_D; else lie.algebra_type=LiE::LiE_t::alg_B; lie.algebra_dim=dims/2; lie.start(); // Find the representation for each group of tensors, taking into // account their exchange symmetries. std::vector groupreps; for(unsigned int i=0; i1) { assert(idts[i].tab); // Every tensor with 2+ indices needs a TableauSymmetry. TableauBase::tab_t thetab=idts[i].tab->get_tab(tr, idts[i].tensors[0], 0); std::vector topleth; for(unsigned int rws=0; rwssign()==-1) ++sign; lie.alt_sym_tensor(idts[i].tensors.size(), single_tensor_rep, multi_tensor_rep, sign%2==0); groupreps.push_back(multi_tensor_rep); } } // Now tensor the whole lot together. LiE::LiE_t::reps_t result=groupreps[0], tmpstore; for(unsigned int i=0; i >& gs) { std::vector idts; int total_number_of_indices=collect_identical_tensors(tr, it, idts); if(idts.size()==0) return true; // no indices, so nothing to permute // Make a strong generating set for the permutation of identical tensors. for(unsigned int i=0; isign()==0) continue; if(num>1) { std::vector gsel(total_number_of_indices+2); for(unsigned int sobj=0; sobj sobj. for(unsigned int obj=sobj; objsign()==-1) std::swap(gsel[total_number_of_indices], gsel[total_number_of_indices+1]); } if(idts[i].spino && idts[i].number_of_indices==0) { if(gsel[total_number_of_indices+1]==total_number_of_indices+1) return false; } else gs.push_back(gsel); } } } } // for(unsigned int i=0; i1) { // for(int t1=0; t1 gsel(total_number_of_indices+2); // for(int kk=0; kksign()==-1) { // // txtout << "anticommuting" << std::endl; // std::swap(gsel[total_number_of_indices], gsel[total_number_of_indices+1]); // } // else if(idts[i].comm->sign()==0) // return false; // } // // if(idts[i].spino && idts[i].number_of_indices==0) { // if(gsel[total_number_of_indices+1]==total_number_of_indices+1) // return false; // } // else gs.push_back(gsel); // } // } // } // } return true; } bool operator<(const exchange::tensor_type_t& one, const exchange::tensor_type_t& two) { if(*one.name < *two.name) return true; if(one.name == two.name) if(one.number_of_indices < two.number_of_indices) return true; return false; } cadabra-1.39/src/exchange.hh000066400000000000000000000046201234107666300157270ustar00rootroot00000000000000/* Cadabra: a field-theory motivated computer algebra system. Copyright (C) 2001-2011 Kasper Peeters 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 3 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, see . */ /** Functions to handle the exchange properties of two or more symbols in a product. This module is only concerned with the exchange properties of tensors as a whole, not with index permutation symmetries (which are handled in the canonicalise class of algebra.cc). */ #ifndef exchange_hh_ #define exchange_hh_ #include "storage.hh" #include #include "modules/algebra.hh" #include "modules/gamma.hh" class exchange { public: struct identical_tensors_t { unsigned int number_of_indices; std::vector tensors; std::vector seq_numbers_of_first_indices; const SelfCommutingBehaviour *comm; const Spinor *spino; const TableauBase *tab; const Traceless *traceless; const GammaTraceless *gammatraceless; int extra_sign; }; // Obtain index exchange symmetries under tensor permutation. Returns 'false' if // an identically zero expression is encountered. static int collect_identical_tensors(exptree& tr, exptree::iterator it, std::vector& idts); static unsigned int possible_singlets(exptree&, exptree::iterator); static bool get_node_gs(exptree&, exptree::iterator, std::vector >& ); // static void get_index_gs(exptree::iterator, std::vector >& ); struct tensor_type_t { nset_t::iterator name; unsigned int number_of_indices; }; }; bool operator<(const exchange::tensor_type_t& one, const exchange::tensor_type_t& two); #endif cadabra-1.39/src/main.cc000066400000000000000000000275601234107666300150670ustar00rootroot00000000000000/* Cadabra: a field-theory motivated computer algebra system. Copyright (C) 2001-2011 Kasper Peeters 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 3 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, see . */ /** \mainpage Cadabra \author Kasper Peeters \version development \date latest \see http://cadabra.phi-sci.com/ Cadabra: a field-theory motivated approach to computer algebra. The core of the manipulator is stored in the following files - main.cc - manipulator.hh and manipulator.cc - algorithm.hh and algorithm.cc - display.hh and display.cc - settings.hh and settings.cc - preprocessor.hh and preprocessor.cc - parser.hh and parser.cc - props.hh and props.cc - exchange.hh and exchange.cc - storage.hh and storage.cc Further code is in the src/modules directory. */ #include "storage.hh" #include "props.hh" #include "manipulator.hh" #include #include #include "stopwatch.hh" #include #include #include #include #include #include #include #include #include #include #include #include // prompt does not do non-standard pipe names yet, so therefore the hack: modglue::ipipe commands("stdin"); modglue::opipe raw_txtout("stdout"); modglue::opipe texout("stderr"); std::ofstream debugout; std::ofstream nullout("/dev/null",std::ios::app); std::ostream *real_txtout; std::ostream *fake_txtout; std::ostream *real_forcedout; std::ostream *fake_forcedout; #define txtout (*fake_txtout) #define forcedout (*fake_forcedout) // global flag to indicate a control-C interrupt. bool interrupted=false; stopwatch globaltime; unsigned int size_x, size_y; bool loginput=false; bool nowarnings=false; bool silentfail=false; std::vector cmdline_arguments; extern std::string defaults; void sigc_handler(int num) { interrupted=true; signal(SIGINT,sigc_handler); } void determine_window_size() { struct winsize tmp; if (ioctl( 0, TIOCGWINSZ, &tmp)==-1) { // debugout << "cannot determine window size" << std::endl; size_x=80; size_y=24; } else { size_x=tmp.ws_col; size_y=tmp.ws_row; } // debugout << "window size now " << size_x << "x" << size_y << std::endl; } void winch_handler(int num) { debugout << "window size changed" << std::endl; determine_window_size(); } bool verify_tool_presence() { return true; } int main(int argc, char **argv) { std::string inputfile; char hostname[256]; gethostname(hostname, 255); char *pbs_job=getenv("PBS_JOBID"); std::string logname=std::string("cdb_")+hostname+(pbs_job==0?"":std::string("_")+pbs_job) +std::string(".log"); char *cdblog=getenv("CDB_LOG"); if(cdblog==0) debugout.open("/dev/null", std::ios::app); else switch(atoi(cdblog)) { case 1: debugout.open(logname.c_str(), std::ios::app); break; case 2: debugout.open("/dev/tty", std::ios::app); break; } signal(SIGINT,sigc_handler); signal(SIGWINCH, winch_handler); real_txtout=&raw_txtout; real_forcedout=&raw_txtout; modglue::main mm(argc, argv); manipulator mnp; bool disable_defaults=false; bool disable_dot_cadabra=false; bool continue_interactive=false; for(int i=1; i 0.8>" << std::endl; txtout << DATA_BEGIN << "latex:"; txtout << "\\rm {\\Large Cadabra " << RELEASE << "} ("; #ifdef STATICBUILD txtout << "static, "; #endif txtout << "built on " << HOSTNAME << " " << DATETIME << ")\\\\" << std::endl; txtout << "Copyright (c) 2001-2011 Kasper Peeters \\\\" << std::endl; txtout << "Available under the terms of the GNU General Public License.\\\\" << std::endl; } else { txtout << "Cadabra " << RELEASE << " ("; #ifdef STATICBUILD txtout << "static, "; #endif txtout << "built on " << HOSTNAME << " " << DATETIME << ")" << std::endl << "Copyright (C) 2001-2011 Kasper Peeters " << std::endl << "Info at http://cadabra.phi-sci.com/" << std::endl << "Available under the terms of the GNU General Public License." << std::endl << std::endl; } debugout << "-----" << std::endl << "Cadabra (compiled " << DATETIME << " on " << HOSTNAME << ")" << std::endl; // Process default startup file (included in the binary). if(!disable_defaults) { std::istringstream tst(defaults); real_txtout=&nullout; fake_txtout=real_txtout; mnp.open_stream(&tst); mnp.handle_input(); (*real_txtout) << std::flush; real_txtout=&raw_txtout; fake_txtout=real_txtout; } // Process user startup file, if any. if(!disable_dot_cadabra) { std::string defname=getenv("HOME"); defname+="/.cadabra"; std::ifstream tst(defname.c_str()); if(tst.is_open()) { tst.close(); mnp.open_stream(defname); mnp.handle_input(); } else debugout << "Default startup file ~/.cadabra not present." << std::endl << std::endl; } if(mnp.eo.output_format==exptree_output::out_texmacs) txtout << DATA_END << std::flush; // Process input file, if any. if(inputfile.size()>0) { int orig_fd=open(inputfile.c_str(), O_RDONLY); if(orig_fd!=-1) { // make a temporary copy char temp_name[]="/tmp/cdbtmp_XXXXXX"; int temp_fd=mkstemp(temp_name); if(temp_fd!=-1) { char buffer[8192]; ssize_t read_len; while((read_len=read(orig_fd, buffer, 8192))!=0) { ssize_t start=0; do { ssize_t written=write(temp_fd, &(buffer[start]), read_len); if(written>=0) { start-=written; read_len-=written; } if(written<0 && errno!=EINTR) { close(orig_fd); close(temp_fd); txtout << "Failure while writing temporary copy of the input file to " << temp_name << std::endl; close(orig_fd); close(temp_fd); return(-1); } } while(read_len>0); } close(orig_fd); close(temp_fd); mnp.open_stream(temp_name); unlink(temp_name); // immediately unlink, so that the tmp file goes away in case of crash/abort } else { txtout << "Failed to make temporary copy of the input file." << std::endl; return -1; } } else { txtout << "Input file " << inputfile << " not found." << std::endl; return -1; } } // int oldin; // if(isatty(0)==0) { // oldin=dup(0); // txtout << oldin << std::endl; // } // Run main loop. mainloop: if(inputfile.size()==0) mnp.print_prompt(); bool reading_input_file=false; try { if(inputfile.size()==0) mm.run(1); else { reading_input_file=true; inputfile=""; mnp.handle_input(); } } catch(stream_end_error& se) { txtout << "Normal stream ended" << std::endl; if(continue_interactive) { commands.clear(); assert(reading_input_file==false); // We were reading a redirected stdin, we have to reopen the tty. if(freopen("/dev/tty","r",stdin)==NULL) { txtout << "Failed to reopen tty." << std::endl; return_value=-1; } else goto mainloop; } else return_value=-2; } catch(std::exception& ex) { txtout << std::endl; txtout << "FATAL: " << ex.what() << std::endl; if(getenv("CDB_LOG")) txtout << " See the log file \"" << logname << "\" for more details." << std::endl; else txtout << " Rerun with the CDB_LOG environment variable set, to generate a log." << std::endl; txtout << std::endl; // FIXME: output is still screwed up, perhaps we should set fcntl stuff back. // Although it seems that this output only arrives when using prompt. return_value=-1; } catch(exit_exception& ex) { txtout << "Cadabra exiting"; if(getenv("CDB_LOG")) txtout << "; log written on \"" << logname << "\"." << std::endl; else txtout << "." << std::endl; return_value=0; } if(reading_input_file) { txtout << "Input file ended" << std::endl; reading_input_file=false; if(continue_interactive) { txtout << "Continuing interactively" << std::endl; commands.clear(); if(freopen("/dev/tty","r",stdin)==NULL) txtout << "Failed to re-open stdin."; else goto mainloop; } } else if(isatty(0)==0) { txtout << "Redirected input ended." << std::endl; if(continue_interactive) { txtout << "Continuing interactively" << std::endl; commands.clear(); assert(reading_input_file==false); // We were reading a redirected stdin, we have to reopen the tty. // FIXME: this fails, though it used to work. if(freopen("/dev/tty","r",stdin)==NULL) { txtout << "Failed to re-open stdin."; } else goto mainloop; } } debugout << "-----" << std::endl; } // Funny things appear on the output if we do not flush here... std::cout << std::flush; std::cerr << std::flush; raw_txtout << std::flush; texout << std::flush; return return_value; } cadabra-1.39/src/manipulator.cc000066400000000000000000001413731234107666300164750ustar00rootroot00000000000000/* Cadabra: a field-theory motivated computer algebra system. Copyright (C) 2001-2011 Kasper Peeters 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 3 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, see . */ #include #include #include #include "modules/modules.hh" #include "manipulator.hh" #include "preprocessor.hh" #include "settings.hh" #include "parser.hh" #include extern std::string defaults; stream_end_error::stream_end_error() { } exit_exception::exit_exception() { } manipulator::algo_info::algo_info(std::auto_ptr (*cr)(exptree&, iterator)) : create(cr), calls(0) { } manipulator::manipulator() : eo(expressions, exptree_output::out_plain), getline_was_eof(0), editing_equation(0), last_used_equation_number(0), utf8_output(getenv("CDB_USE_UTF8")), status_output(false), prompt_string(">") { properties::register_properties(); settings::register_properties(); // pertstring algorithms["@aticksen"] =new algo_info(&create); algorithms["@riemannid"] =new algo_info(&create); // tableaux tableaux::register_properties(); algorithms["@lr_tensor"] =new algo_info(&create); algorithms["@tabdimension"] =new algo_info(&create); algorithms["@tabcanonicalise"] =new algo_info(&create); algorithms["@tabstandardform"] =new algo_info(&create); algorithms["@decompose_product"] =new algo_info(&create); algorithms["@young_project_product"] =new algo_info(&create); // algebra algebra::register_properties(); algorithms["@distribute"] =new algo_info(&create); algorithms["@expand_power"] =new algo_info(&create); algorithms["@prodrule"] =new algo_info(&create); algorithms["@prodflatten"] =new algo_info(&create); algorithms["@sumflatten"] =new algo_info(&create); algorithms["@listflatten"] =new algo_info(&create); algorithms["@remove_indexbracket"] =new algo_info(&create); algorithms["@prodcollectnum"] =new algo_info(&create); algorithms["@collect_terms"] =new algo_info(&create); algorithms["@collect_factors"]=new algo_info(&create); algorithms["@factorise"] =new algo_info(&create); algorithms["@factor_in"] =new algo_info(&create); algorithms["@factor_out"] =new algo_info(&create); algorithms["@canonicalise"] =new algo_info(&create); algorithms["@reduce"] =new algo_info(&create); algorithms["@ratrewrite"] =new algo_info(&create); algorithms["@canonicalorder"] =new algo_info(&create); algorithms["@acanonicalorder"]=new algo_info(&create); algorithms["@prodsort"] =new algo_info(&create); algorithms["@sumsort"] =new algo_info(&create); algorithms["@spinorsort"] =new algo_info(&create); // algorithms["@subseq"] =new algo_info(&create); // algorithms["@drop"] =new algo_info(&create); algorithms["@drop_weight"] =new algo_info(&create); algorithms["@keep_weight"] =new algo_info(&create); algorithms["@sym"] =new algo_info(&create); algorithms["@asym"] =new algo_info(&create); algorithms["@"] =new algo_info(&create); algorithms["@indexsort"] =new algo_info(&create); algorithms["@asymprop"] =new algo_info(&create); algorithms["@impose_asym"] =new algo_info(&create); algorithms["@young_project"] =new algo_info(&create); algorithms["@young_project_tensor"] =new algo_info(&create); algorithms["@keep_terms"] =new algo_info(&create); // linear algorithms["@lsolve"] =new algo_info(&create); algorithms["@decompose"] =new algo_info(&create); // combinat algorithms["@permute"] =new algo_info(&create); // convert algorithms["@from_math"] =new algo_info(&create); // not documented yet algorithms["@from_maple"] =new algo_info(&create); // not documented yet algorithms["@run"] =new algo_info(&create); algorithms["@maxima"] =new algo_info(&create); algorithms["@maple"] =new algo_info(&create); // differential geometry diff_geometry::register_properties(); // gamma gamma_algebra::register_properties(); algorithms["@join"] =new algo_info(&create); algorithms["@projweyl"] =new algo_info(&create); algorithms["@remove_gamma_trace"]=new algo_info(&create); // not documented yet algorithms["@gammasplit"] = new algo_info(&create); algorithms["@rewrite_diracbar"] = new algo_info(&create); algorithms["@fierz"] = new algo_info(&create); // field_theory field_theory::register_properties(); algorithms["@eliminate_kr"] =new algo_info(&create); algorithms["@einsteinify"] =new algo_info(&create); algorithms["@combine"] =new algo_info(&create); algorithms["@expand"] =new algo_info(&create); algorithms["@debracket"] =new algo_info(&create); // not documented yet (what is it?) algorithms["@reduce_gendelta"] =new algo_info(&create); algorithms["@breakgendelta"] =new algo_info(&create); algorithms["@eliminateeps"] =new algo_info(&create); // buggy algorithms["@dualise_tensor"] =new algo_info(&create); algorithms["@epsprod2gendelta"]=new algo_info(&create); algorithms["@product_shorthand"]=new algo_info(&create); algorithms["@expand_product_shorthand"]=new algo_info(&create); algorithms["@remove_eoms"] =new algo_info(&create); // not documented yet (deprecate?) algorithms["@pintegrate"] =new algo_info(&create); algorithms["@impose_bianchi"] =new algo_info(&create); algorithms["@all_contractions"]=new algo_info(&create); algorithms["@unique_indices"] =new algo_info(&create); // not properly specified // algorithms["@remove_vanishing_derivatives"] =new algo_info(&create); algorithms["@unwrap"] =new algo_info(&create); // dummies algorithms["@rename_dummies"] =new algo_info(&create); // select // algorithms["@select"] =&create